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 2015/08/20 00:53:49 UTC

[01/36] incubator-brooklyn git commit: Rename o.a.b.util.groovy.internal to o.a.b.util.groovy

Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master dbf621a84 -> 147f9ec44


Rename o.a.b.util.groovy.internal to o.a.b.util.groovy


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

Branch: refs/heads/master
Commit: 0eab0fa05e4b9f700cef855e974971faf494116c
Parents: dbf621a
Author: Aled Sage <al...@gmail.com>
Authored: Wed Aug 19 22:31:05 2015 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Wed Aug 19 22:31:24 2015 +0100

----------------------------------------------------------------------
 .../util/core/BrooklynLanguageExtensions.java   |   2 +-
 .../brooklyn/util/core/internal/Repeater.java   |   2 +-
 .../util/core/internal/RepeaterTest.groovy      |   4 +-
 .../Infinispan5ServerIntegrationTest.groovy     |   2 +-
 .../nosql/couchdb/AbstractCouchDBNodeTest.java  |   2 +-
 .../webapp/WebAppLiveIntegrationTest.groovy     |   2 +-
 ...namicWebAppClusterRebindIntegrationTest.java |   2 +-
 .../brooklyn/util/groovy/JavadocDummy.java      |  30 ++
 .../brooklyn/util/groovy/LanguageUtils.groovy   | 383 +++++++++++++++++++
 .../brooklyn/util/groovy/TimeExtras.groovy      |  83 ++++
 .../util/groovy/internal/JavadocDummy.java      |  30 --
 .../util/groovy/internal/LanguageUtils.groovy   | 383 -------------------
 .../util/groovy/internal/TimeExtras.groovy      |  83 ----
 .../util/groovy/LanguageUtilsTest.groovy        | 152 ++++++++
 .../brooklyn/util/groovy/PojoTestingFields.java |  28 ++
 .../brooklyn/util/groovy/TimeExtrasTest.groovy  |  49 +++
 .../groovy/internal/LanguageUtilsTest.groovy    | 153 --------
 .../util/groovy/internal/PojoTestingFields.java |  28 --
 .../util/groovy/internal/TimeExtrasTest.groovy  |  51 ---
 19 files changed, 733 insertions(+), 736 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/core/src/main/java/org/apache/brooklyn/util/core/BrooklynLanguageExtensions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/BrooklynLanguageExtensions.java b/core/src/main/java/org/apache/brooklyn/util/core/BrooklynLanguageExtensions.java
index 5e7f0a6..afad73f 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/BrooklynLanguageExtensions.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/BrooklynLanguageExtensions.java
@@ -21,7 +21,7 @@ package org.apache.brooklyn.util.core;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.brooklyn.core.internal.BrooklynInitialization;
-import org.apache.brooklyn.util.groovy.internal.TimeExtras;
+import org.apache.brooklyn.util.groovy.TimeExtras;
 
 /** @deprecated since 0.7.0 use {@link BrooklynInitialization} */
 public class BrooklynLanguageExtensions {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/core/src/main/java/org/apache/brooklyn/util/core/internal/Repeater.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/internal/Repeater.java b/core/src/main/java/org/apache/brooklyn/util/core/internal/Repeater.java
index bc54b6e..77d15c7 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/internal/Repeater.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/internal/Repeater.java
@@ -30,7 +30,7 @@ import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.flags.FlagUtils;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.groovy.internal.TimeExtras;
+import org.apache.brooklyn.util.groovy.TimeExtras;
 import org.apache.brooklyn.util.time.Duration;
 import org.apache.brooklyn.util.time.Time;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/core/src/test/java/org/apache/brooklyn/util/core/internal/RepeaterTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/internal/RepeaterTest.groovy b/core/src/test/java/org/apache/brooklyn/util/core/internal/RepeaterTest.groovy
index 5888aa0..5eae3c9 100644
--- a/core/src/test/java/org/apache/brooklyn/util/core/internal/RepeaterTest.groovy
+++ b/core/src/test/java/org/apache/brooklyn/util/core/internal/RepeaterTest.groovy
@@ -25,8 +25,8 @@ import java.util.concurrent.Callable;
 import java.util.concurrent.TimeUnit
 
 import org.testng.annotations.Test
-import org.apache.brooklyn.util.core.internal.Repeater;
-import org.apache.brooklyn.util.groovy.internal.TimeExtras;
+import org.apache.brooklyn.util.core.internal.Repeater
+import org.apache.brooklyn.util.groovy.TimeExtras;
 import org.apache.brooklyn.util.time.Duration;
 
 import com.google.common.base.Stopwatch

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5ServerIntegrationTest.groovy
----------------------------------------------------------------------
diff --git a/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5ServerIntegrationTest.groovy b/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5ServerIntegrationTest.groovy
index b283f2f..1e68c27 100644
--- a/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5ServerIntegrationTest.groovy
+++ b/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5ServerIntegrationTest.groovy
@@ -35,7 +35,7 @@ import org.apache.brooklyn.api.entity.Application
 import org.apache.brooklyn.core.entity.Entities
 import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation
 import org.apache.brooklyn.core.test.entity.TestApplicationImpl
-import org.apache.brooklyn.util.groovy.internal.TimeExtras
+import org.apache.brooklyn.util.groovy.TimeExtras;
 import org.apache.brooklyn.util.net.Networking
 import org.apache.brooklyn.util.repeat.Repeater
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/couchdb/AbstractCouchDBNodeTest.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/couchdb/AbstractCouchDBNodeTest.java b/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/couchdb/AbstractCouchDBNodeTest.java
index a4382ce..2ecfac8 100644
--- a/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/couchdb/AbstractCouchDBNodeTest.java
+++ b/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/couchdb/AbstractCouchDBNodeTest.java
@@ -27,7 +27,7 @@ import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
-import org.apache.brooklyn.util.groovy.internal.TimeExtras;
+import org.apache.brooklyn.util.groovy.TimeExtras;
 
 /**
  * CouchDB test framework for integration and live tests.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppLiveIntegrationTest.groovy
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppLiveIntegrationTest.groovy b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppLiveIntegrationTest.groovy
index 6bb41cf..c8747fa 100644
--- a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppLiveIntegrationTest.groovy
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppLiveIntegrationTest.groovy
@@ -37,7 +37,7 @@ import org.apache.brooklyn.entity.webapp.jboss.JBoss7ServerImpl
 import org.apache.brooklyn.entity.webapp.tomcat.TomcatServer
 import org.apache.brooklyn.entity.webapp.tomcat.TomcatServerImpl
 import org.apache.brooklyn.test.TestUtils
-import org.apache.brooklyn.util.groovy.internal.TimeExtras
+import org.apache.brooklyn.util.groovy.TimeExtras;
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
 import org.testng.annotations.AfterMethod

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/ControlledDynamicWebAppClusterRebindIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/ControlledDynamicWebAppClusterRebindIntegrationTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/ControlledDynamicWebAppClusterRebindIntegrationTest.java
index a4dec8c..b05a747 100644
--- a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/ControlledDynamicWebAppClusterRebindIntegrationTest.java
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/ControlledDynamicWebAppClusterRebindIntegrationTest.java
@@ -41,7 +41,7 @@ import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster;
 import org.apache.brooklyn.test.WebAppMonitor;
 import org.apache.brooklyn.test.support.TestResourceUnavailableException;
-import org.apache.brooklyn.util.groovy.internal.TimeExtras;
+import org.apache.brooklyn.util.groovy.TimeExtras;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.annotations.AfterMethod;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/JavadocDummy.java
----------------------------------------------------------------------
diff --git a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/JavadocDummy.java b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/JavadocDummy.java
new file mode 100644
index 0000000..c9a51b5
--- /dev/null
+++ b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/JavadocDummy.java
@@ -0,0 +1,30 @@
+/*
+ * 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.util.groovy;
+
+/** Maven Central requires javadoc to promote as a release. This seemed to happen when this was built by maven as a bundle,
+ * but now that it is built as a jar it does not. This class exists only to provide that javadoc.
+ * <p>
+ * Note the groovy code does javadoc but the maven build is not picking it up. It *is* generated as part of the site build.
+ */
+public class JavadocDummy {
+
+    private JavadocDummy() {}
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/LanguageUtils.groovy
----------------------------------------------------------------------
diff --git a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/LanguageUtils.groovy b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/LanguageUtils.groovy
new file mode 100644
index 0000000..d4fe86c
--- /dev/null
+++ b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/LanguageUtils.groovy
@@ -0,0 +1,383 @@
+/*
+ * 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.util.groovy
+
+import java.lang.reflect.Field
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier
+import java.util.Collection;
+import java.util.concurrent.atomic.AtomicLong
+
+import org.apache.brooklyn.util.javalang.Reflections;
+import org.apache.brooklyn.util.text.Identifiers
+
+import com.google.common.annotations.Beta
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+
+/**
+ * Useful Groovy utility methods.
+ * 
+ * @deprecated since 0.5; requires thorough review for what will be kept.
+ *             e.g. consider instead using guava's {@link com.google.common.collect.Multimap} instead of addToMapOfSets etc
+ */
+@Deprecated
+@Beta
+public class LanguageUtils {
+    // For unique identifiers
+    private static final AtomicLong seed = new AtomicLong(0L)
+
+    public static <T> T getRequiredField(String name, Map<?,?> m) {
+        if (!m.containsKey(name))
+            throw new IllegalArgumentException("a parameter '"+name+"' was required in the argument to this function")
+        m.get name
+    }
+
+    public static <T> T getOptionalField(String name, Map<?,?> m, T defaultValue=null) {
+        m.get(name) ?: defaultValue
+    }
+
+    public static <T> T getPropertySafe(Object target, String name, T defaultValue=null) {
+        target.hasProperty(name)?.getProperty(target) ?: defaultValue
+    }
+
+    //TODO find with annotation
+
+    public static byte[] serialize(Object orig) {
+        if (orig == null) return null;
+
+        // Write the object out to a byte array
+        ByteArrayOutputStream fbos = []
+        ObjectOutputStream out = new ObjectOutputStream(fbos);
+        out.writeObject(orig);
+        out.flush();
+        out.close();
+        return fbos.toByteArray();
+    }
+
+    public static <T> T deserialize(byte[] bytes, ClassLoader classLoader) {
+        if (bytes == null) return null;
+
+        ObjectInputStream ins =
+                //new ObjectInputStreamWithLoader(new FastByteArrayInputStream(bytes, bytes.length), classLoader);
+                new ObjectInputStream(new ByteArrayInputStream(bytes));
+        (T) ins.readObject();
+    }
+
+    /**
+     * @deprecated use Identifiers.makeRandomId(8)
+     */
+    @Deprecated
+    public static String newUid() { Identifiers.makeRandomId(8) }
+
+    public static Map setFieldsFromMap(Object target, Map fieldValues) {
+        Map unused = [:]
+        fieldValues.each {
+            //            println "looking for "+it.key+" in "+target+": "+target.metaClass.hasProperty(it.key)
+            target.hasProperty(it.key) ? target.(it.key) = it.value : unused << it
+        }
+        unused
+    }
+
+    /**
+     * Adds the given value to a collection in the map under the key.
+     * 
+     * A collection (as {@link LinkedHashMap}) will be created if necessary,
+     * synchronized on map for map access/change and set for addition there
+     *
+     * @return the updated set (instance, not copy)
+     * 
+     * @deprecated since 0.5; use {@link HashMultimap}, and {@link Multimaps#synchronizedSetMultimap(com.google.common.collect.SetMultimap)}
+     */
+    @Deprecated
+    public static <K,V> Set<V> addToMapOfSets(Map<K,Set<V>> map, K key, V valueInCollection) {
+        Set<V> coll;
+        synchronized (map) {
+            coll = map.get(key)
+            if (coll==null) {
+                coll = new LinkedHashSet<V>()
+                map.put(key, coll)
+            }
+            if (coll.isEmpty()) {
+                synchronized (coll) {
+                    coll.add(valueInCollection)
+                }
+                //if collection was empty then add to the collection while holding the map lock, to prevent removal
+                return coll
+            }
+        }
+        synchronized (coll) {
+            if (!coll.isEmpty()) {
+                coll.add(valueInCollection)
+                return coll;
+            }
+        }
+        //if was empty, recurse, because someone else might be removing the collection
+        return addToMapOfSets(map, key, valueInCollection);
+    }
+
+    /**
+     * as {@link #addToMapOfSets(Map, Object, Object)} but for {@link ArrayList}
+     * 
+     * @deprecated since 0.5; use {@link ArrayListMultimap}, and {@link Multimaps#synchronizedListMultimap(com.google.common.collect.ListMultimap)}
+     */
+    @Deprecated
+    public static <K,V> List<V> addToMapOfLists(Map<K,List<V>> map, K key, V valueInCollection) {
+        List<V> coll;
+        synchronized (map) {
+            coll = map.get(key)
+            if (coll==null) {
+                coll = new ArrayList<V>()
+                map.put(key, coll)
+            }
+            if (coll.isEmpty()) {
+                synchronized (coll) {
+                    coll.add(valueInCollection)
+                }
+                //if collection was empty then add to the collection while holding the map lock, to prevent removal
+                return coll
+            }
+        }
+        synchronized (coll) {
+            if (!coll.isEmpty()) {
+                coll.add(valueInCollection)
+                return coll;
+            }
+        }
+        //if was empty, recurse, because someone else might be removing the collection
+        return addToMapOfLists(map, key, valueInCollection);
+    }
+
+    /**
+     * Removes the given value from a collection in the map under the key.
+     *
+     * @return the updated set (instance, not copy)
+     * 
+     * @deprecated since 0.5; use {@link ArrayListMultimap} or {@link HashMultimap}, and {@link Multimaps#synchronizedListMultimap(com.google.common.collect.ListMultimap)} etc
+     */
+    @Deprecated
+    public static <K,V> boolean removeFromMapOfCollections(Map<K,? extends Collection<V>> map, K key, V valueInCollection) {
+        Collection<V> coll;
+        synchronized (map) {
+            coll = map.get(key)
+            if (coll==null) return false;
+        }
+        boolean result;
+        synchronized (coll) {
+            result = coll.remove(valueInCollection)
+        }
+        if (coll.isEmpty()) {
+            synchronized (map) {
+                synchronized (coll) {
+                    if (coll.isEmpty()) {
+                        //only remove from the map if no one is adding to the collection or to the map, and the collection is still in the map
+                        if (map.get(key)==coll) {
+                            map.remove(key)
+                        }
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Visits all fields of a given object, recursively.
+     *
+     * For collections, arrays, and maps it visits the items within, passing null for keys where it isn't a map.
+     */
+    public static void visitFields(Object o, FieldVisitor fv, Collection<Object> objectsToSkip=([] as Set)) {
+        if (o == null || objectsToSkip.contains(o)) return
+        objectsToSkip << o
+        if (o in String) return
+        if (o in Map) {
+            o.each { key, value ->
+                fv.visit(o, key.toString(), value)
+                visitFields(value, fv, objectsToSkip)
+            }
+        } else if ((o in Collection) || (o.getClass().isArray())) {
+            o.each {
+                entry ->
+                fv.visit(o, null, entry)
+                visitFields(entry, fv, objectsToSkip)
+            }
+        } else {
+            o.getClass().getDeclaredFields().each {
+                Field field ->
+                if ((field.getModifiers() & Modifier.STATIC) || field.isSynthetic()) return;  //skip static
+                field.setAccessible true
+                def v = field.get(o);
+                fv.visit(o, field.name, v)
+                visitFields(v, fv, objectsToSkip)
+            }
+        }
+    }
+
+    public interface FieldVisitor {
+        /** Invoked by visitFields; fieldName will be null for collections */
+        public void visit(Object parent, String fieldName, Object value)
+    }
+
+    /**
+     * Iterates through two collections simultaneously, passing both args to code.
+     * 
+     * <pre>
+     * a = ['a','b']; b=[1,2];
+     * assert ['a1','b2'] == forboth(a,b) { x,y -> x+y }
+     * </pre>
+     */
+    public static Collection forBoth(Collection l1, Collection l2, Closure code) {
+        def result=[]
+        l1.eachWithIndex { a, i -> result.add( code.call(a, l2[i]) ) }
+        result
+    }
+
+    public static Collection forBothWithIndex(Collection l1, Collection l2, Closure code) {
+        def result=[]
+        l1.eachWithIndex { a, i -> result.add( code.call(a, l2[i], i) ) }
+        result
+    }
+
+    public static Collection forBoth(Object[] l1, Object[] l2, Closure code) {
+        def result=[]
+        l1.eachWithIndex { a, i -> result.add( code.call(a, l2[i]) ) }
+        result
+    }
+
+    public static Collection forBothWithIndex(Object[] l1, Object[] l2, Closure code) {
+        def result=[]
+        l1.eachWithIndex { a, i -> result.add( code.call(a, l2[i], i) ) }
+        result
+    }
+
+    /** return value used to indicate that there is no such field */
+    public static final Object NO_SUCH_FIELD = new Object();
+
+    /**
+     * Default field getter.
+     *
+     * Delegates to {@code object[field]} (which will invoke a getter if one exists, in groovy),
+     * unless field starts with {@literal @} in which case it looks up the actual java field (bypassing getter).
+     * <p>
+     * Can be extended as needed when passed to {@link #equals(Object, Object, Class, String[])}
+     */
+    public static final Closure DEFAULT_FIELD_GETTER = { Object object, Object field ->
+        try {
+            if ((field in String) && field.startsWith("@")) {
+                return object.@"${field.substring(1)}"
+            }
+            return object[field]
+        } catch (Exception e) {
+            return NO_SUCH_FIELD
+        }
+    }
+
+    /**
+     * Checks equality of o1 and o2 with respect to the named fields, optionally enforcing a common superclass
+     * and using a custom field-getter.
+     *
+     * Other types can be supplied if they are supported by {@code object[field]} (what the {@link #DEFAULT_FIELD_GETTER} does)
+     * or if the {@literal optionalGetter} handles it. Note that {@code object[field]} causes invocation of {@code object.getAt(field)}
+     * (which can be provided on the object for non-strings - this is preferred to an optionalGetter, generally)
+     * looking for {@code object.getXxx()}, where field is a string {@literal xxx}, then {@code object.xxx}.
+     * <p>
+     * One exception is that field names which start with {@literal @} get the field directly according to {@link #DEFAULT_FIELD_GETTER},
+     * but use with care on private fields, as they must be on the object and not a superclass, and with groovy properties
+     * (formerly known as package-private, i.e. with no access modifiers) because they become private fields.
+     * <p>
+     * For example
+     * <pre>
+     * public class Foo {
+     *   Object bar;
+     *   public boolean equals(Object other) { LangaugeUtils.equals(this, other, Foo.class, ["bar"]); }
+     *   public int hashCode() { LangaugeUtils.hashCode(this, ["bar"]); }
+     * }
+     * </pre>
+     *
+     * @param o1 one object to compare
+     * @param o2 other object to compare
+     * @param optionalCommonSuperClass if supplied, returns false unless both objects are instances of the given type;
+     *     (if not supplied it effectively does duck typing, returning false if any field is not present)
+     * @param optionalGetter if supplied, a closure which takes (object, field) and returns the value of field on object;
+     *  should return static {@link #NO_SUCH_FIELD} if none found;
+     *  recommended to delegate to {@link #DEFAULT_FIELD_GETTER} at least for strings (or for anything)
+     * @param fields typically a list of strings being names of fields on the class to compare
+     * @return true if the two objects are equal in all indicated fields, and conform to the optionalCommonSuperClass if supplied
+     */
+    public static boolean equals(Object o1, Object o2, Class<?> optionalCommonSuperClass=null, Closure optionalGetter=null, Iterable<Object> fieldNames) {
+        if (o1==null) return o2==null;
+        if (o2==null) return false;
+        if (optionalCommonSuperClass) {
+            if (!(o1 in optionalCommonSuperClass) || !(o2 in optionalCommonSuperClass)) return false
+        }
+        Closure get = optionalGetter ?: DEFAULT_FIELD_GETTER
+        for (it in fieldNames) {
+            def v1 = get.call(o1, it)
+            if (v1==NO_SUCH_FIELD) return false
+            if (v1!=get.call(o2, it)) return false
+        }
+        return true
+    }
+
+    public static boolean equals(Object o1, Object o2, Class<?> optionalCommonSuperClass=null, Closure optionalGetter=null, Object[] fieldNames) {
+        return equals(o1, o2, optionalCommonSuperClass, optionalGetter, Arrays.asList(fieldNames) )
+    }
+
+    /**
+     * Generates a hashcode for an object.
+     * 
+     * Similar to {@link com.google.common.base.Objects#hashCode()} but taking field <em>names</em> and an optional getter,
+     * with the same rich groovy semantics as described in {@link #equals(Object, Object, Class)}.
+     */
+    public static int hashCode(Object o, Closure optionalGetter=null, Collection<Object> fieldNames) {
+        if (o==null) return 0;
+        Closure get = optionalGetter ?: DEFAULT_FIELD_GETTER
+        int result = 1;
+        for (it in fieldNames) {
+            def v1 = get.call(o, it)
+            if (v1==NO_SUCH_FIELD)
+                throw new NoSuchFieldError("Cannot access $it on "+o.getClass());
+            result = 31 * result + (it == null ? 0 : it.hashCode());
+        }
+        result
+    }
+
+    public static int hashCode(Object o, Closure optionalGetter=null, Object[] fieldNames) {
+        hashCode(o, optionalGetter, Arrays.asList(fieldNames))
+    }
+    
+    /** Default String representation is simplified name of class, together with selected fields. */
+    public static String toString(Object o, Closure optionalGetter=null, Collection<? extends CharSequence> fieldNames) {
+        if (o==null) return null;
+        Closure get = optionalGetter ?: DEFAULT_FIELD_GETTER
+        
+        StringBuilder result = new StringBuilder();
+        result.append(o.getClass().getSimpleName());
+        if (result.length() == 0) result.append(o.getClass().getName());
+        List<Object> fieldVals = fieldNames.collect {
+                Object v = get.call(o, it);
+                return (v != null) ? it+"="+v : null;
+        }
+        result.append("[").append(Joiner.on(",").skipNulls().join(fieldVals)).append("]");
+        return result.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/TimeExtras.groovy
----------------------------------------------------------------------
diff --git a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/TimeExtras.groovy b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/TimeExtras.groovy
new file mode 100644
index 0000000..4bca76f
--- /dev/null
+++ b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/TimeExtras.groovy
@@ -0,0 +1,83 @@
+/*
+ * 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.util.groovy
+
+import groovy.time.TimeDuration
+
+import java.util.concurrent.TimeUnit
+
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+
+import org.apache.brooklyn.util.time.Time
+
+
+/**
+ * Classloading this class will cause multiply/add to be made available on TimeDuration.
+ * For example, I could write: 2*TimeUnit.MINUTES+5*TimeUnit.SECONDS.
+ * 
+ * That is why nothing seems to use this class, because the methods it defines are not 
+ * on this class!
+ * 
+ * @author alex
+ * 
+ * @deprecated since 0.6.0 - just use brooklyn.util.time.Duration, simpler and easier to configure, and avoids language problems
+ */
+@Deprecated
+class TimeExtras {
+    public static final Logger log = LoggerFactory.getLogger(TimeExtras.class);
+    
+    public static void init() {
+        Number.metaClass.multiply << { TimeUnit t -> new TimeDuration(t.toMillis(intValue())) }
+        Number.metaClass.multiply << { TimeDuration t -> t.multiply(doubleValue()) }
+        Integer.metaClass.multiply << { TimeUnit t -> new TimeDuration(t.toMillis(intValue())) }
+        
+        TimeDuration.metaClass.multiply << { Number n -> new TimeDuration( (int)(toMilliseconds()*n) ) }
+        TimeDuration.metaClass.constructor << { long millis ->
+            def shift = { int modulus -> int v=millis%modulus; millis/=modulus; v }
+            def l = [shift(1000), shift(60), shift(60), shift(24), (int)millis]
+            Collections.reverse(l)
+            l as TimeDuration
+        }
+    }
+    
+    static { init(); }
+    
+    /** creates a duration object
+     * <p>
+     * fix for irritating classloading/metaclass order 
+     * where an int may get constructed too early and not have the multiply syntax available
+     * (because grail is invoked?; if e.g. 5*SECONDS throws an error, try duration(5, SECONDS)  */ 
+    public static TimeDuration duration(int value, TimeUnit unit) {
+        return new TimeDuration(0, 0, 0, (int)unit.toMillis(value));
+    }
+    
+    public static final TimeDuration ONE_SECOND = duration(1, TimeUnit.SECONDS);
+    public static final TimeDuration FIVE_SECONDS = duration(5, TimeUnit.SECONDS);
+    public static final TimeDuration TEN_SECONDS = duration(10, TimeUnit.SECONDS);
+    public static final TimeDuration THIRTY_SECONDS = duration(30, TimeUnit.SECONDS);
+    public static final TimeDuration ONE_MINUTE = duration(1, TimeUnit.MINUTES);
+    public static final TimeDuration TWO_MINUTES = duration(2, TimeUnit.MINUTES);
+    public static final TimeDuration FIVE_MINUTES = duration(5, TimeUnit.MINUTES);
+
+    public static void sleep(TimeDuration duration) {
+        Time.sleep(duration.toMilliseconds());
+    }    
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/JavadocDummy.java
----------------------------------------------------------------------
diff --git a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/JavadocDummy.java b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/JavadocDummy.java
deleted file mode 100644
index aceef9c..0000000
--- a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/JavadocDummy.java
+++ /dev/null
@@ -1,30 +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.util.groovy.internal;
-
-/** Maven Central requires javadoc to promote as a release. This seemed to happen when this was built by maven as a bundle,
- * but now that it is built as a jar it does not. This class exists only to provide that javadoc.
- * <p>
- * Note the groovy code does javadoc but the maven build is not picking it up. It *is* generated as part of the site build.
- */
-public class JavadocDummy {
-
-    private JavadocDummy() {}
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/LanguageUtils.groovy
----------------------------------------------------------------------
diff --git a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/LanguageUtils.groovy b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/LanguageUtils.groovy
deleted file mode 100644
index 08bc2fe..0000000
--- a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/LanguageUtils.groovy
+++ /dev/null
@@ -1,383 +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.util.groovy.internal
-
-import java.lang.reflect.Field
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier
-import java.util.Collection;
-import java.util.concurrent.atomic.AtomicLong
-
-import org.apache.brooklyn.util.javalang.Reflections;
-import org.apache.brooklyn.util.text.Identifiers
-
-import com.google.common.annotations.Beta
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-
-/**
- * Useful Groovy utility methods.
- * 
- * @deprecated since 0.5; requires thorough review for what will be kept.
- *             e.g. consider instead using guava's {@link com.google.common.collect.Multimap} instead of addToMapOfSets etc
- */
-@Deprecated
-@Beta
-public class LanguageUtils {
-    // For unique identifiers
-    private static final AtomicLong seed = new AtomicLong(0L)
-
-    public static <T> T getRequiredField(String name, Map<?,?> m) {
-        if (!m.containsKey(name))
-            throw new IllegalArgumentException("a parameter '"+name+"' was required in the argument to this function")
-        m.get name
-    }
-
-    public static <T> T getOptionalField(String name, Map<?,?> m, T defaultValue=null) {
-        m.get(name) ?: defaultValue
-    }
-
-    public static <T> T getPropertySafe(Object target, String name, T defaultValue=null) {
-        target.hasProperty(name)?.getProperty(target) ?: defaultValue
-    }
-
-    //TODO find with annotation
-
-    public static byte[] serialize(Object orig) {
-        if (orig == null) return null;
-
-        // Write the object out to a byte array
-        ByteArrayOutputStream fbos = []
-        ObjectOutputStream out = new ObjectOutputStream(fbos);
-        out.writeObject(orig);
-        out.flush();
-        out.close();
-        return fbos.toByteArray();
-    }
-
-    public static <T> T deserialize(byte[] bytes, ClassLoader classLoader) {
-        if (bytes == null) return null;
-
-        ObjectInputStream ins =
-                //new ObjectInputStreamWithLoader(new FastByteArrayInputStream(bytes, bytes.length), classLoader);
-                new ObjectInputStream(new ByteArrayInputStream(bytes));
-        (T) ins.readObject();
-    }
-
-    /**
-     * @deprecated use Identifiers.makeRandomId(8)
-     */
-    @Deprecated
-    public static String newUid() { Identifiers.makeRandomId(8) }
-
-    public static Map setFieldsFromMap(Object target, Map fieldValues) {
-        Map unused = [:]
-        fieldValues.each {
-            //            println "looking for "+it.key+" in "+target+": "+target.metaClass.hasProperty(it.key)
-            target.hasProperty(it.key) ? target.(it.key) = it.value : unused << it
-        }
-        unused
-    }
-
-    /**
-     * Adds the given value to a collection in the map under the key.
-     * 
-     * A collection (as {@link LinkedHashMap}) will be created if necessary,
-     * synchronized on map for map access/change and set for addition there
-     *
-     * @return the updated set (instance, not copy)
-     * 
-     * @deprecated since 0.5; use {@link HashMultimap}, and {@link Multimaps#synchronizedSetMultimap(com.google.common.collect.SetMultimap)}
-     */
-    @Deprecated
-    public static <K,V> Set<V> addToMapOfSets(Map<K,Set<V>> map, K key, V valueInCollection) {
-        Set<V> coll;
-        synchronized (map) {
-            coll = map.get(key)
-            if (coll==null) {
-                coll = new LinkedHashSet<V>()
-                map.put(key, coll)
-            }
-            if (coll.isEmpty()) {
-                synchronized (coll) {
-                    coll.add(valueInCollection)
-                }
-                //if collection was empty then add to the collection while holding the map lock, to prevent removal
-                return coll
-            }
-        }
-        synchronized (coll) {
-            if (!coll.isEmpty()) {
-                coll.add(valueInCollection)
-                return coll;
-            }
-        }
-        //if was empty, recurse, because someone else might be removing the collection
-        return addToMapOfSets(map, key, valueInCollection);
-    }
-
-    /**
-     * as {@link #addToMapOfSets(Map, Object, Object)} but for {@link ArrayList}
-     * 
-     * @deprecated since 0.5; use {@link ArrayListMultimap}, and {@link Multimaps#synchronizedListMultimap(com.google.common.collect.ListMultimap)}
-     */
-    @Deprecated
-    public static <K,V> List<V> addToMapOfLists(Map<K,List<V>> map, K key, V valueInCollection) {
-        List<V> coll;
-        synchronized (map) {
-            coll = map.get(key)
-            if (coll==null) {
-                coll = new ArrayList<V>()
-                map.put(key, coll)
-            }
-            if (coll.isEmpty()) {
-                synchronized (coll) {
-                    coll.add(valueInCollection)
-                }
-                //if collection was empty then add to the collection while holding the map lock, to prevent removal
-                return coll
-            }
-        }
-        synchronized (coll) {
-            if (!coll.isEmpty()) {
-                coll.add(valueInCollection)
-                return coll;
-            }
-        }
-        //if was empty, recurse, because someone else might be removing the collection
-        return addToMapOfLists(map, key, valueInCollection);
-    }
-
-    /**
-     * Removes the given value from a collection in the map under the key.
-     *
-     * @return the updated set (instance, not copy)
-     * 
-     * @deprecated since 0.5; use {@link ArrayListMultimap} or {@link HashMultimap}, and {@link Multimaps#synchronizedListMultimap(com.google.common.collect.ListMultimap)} etc
-     */
-    @Deprecated
-    public static <K,V> boolean removeFromMapOfCollections(Map<K,? extends Collection<V>> map, K key, V valueInCollection) {
-        Collection<V> coll;
-        synchronized (map) {
-            coll = map.get(key)
-            if (coll==null) return false;
-        }
-        boolean result;
-        synchronized (coll) {
-            result = coll.remove(valueInCollection)
-        }
-        if (coll.isEmpty()) {
-            synchronized (map) {
-                synchronized (coll) {
-                    if (coll.isEmpty()) {
-                        //only remove from the map if no one is adding to the collection or to the map, and the collection is still in the map
-                        if (map.get(key)==coll) {
-                            map.remove(key)
-                        }
-                    }
-                }
-            }
-        }
-        return result;
-    }
-
-    /**
-     * Visits all fields of a given object, recursively.
-     *
-     * For collections, arrays, and maps it visits the items within, passing null for keys where it isn't a map.
-     */
-    public static void visitFields(Object o, FieldVisitor fv, Collection<Object> objectsToSkip=([] as Set)) {
-        if (o == null || objectsToSkip.contains(o)) return
-        objectsToSkip << o
-        if (o in String) return
-        if (o in Map) {
-            o.each { key, value ->
-                fv.visit(o, key.toString(), value)
-                visitFields(value, fv, objectsToSkip)
-            }
-        } else if ((o in Collection) || (o.getClass().isArray())) {
-            o.each {
-                entry ->
-                fv.visit(o, null, entry)
-                visitFields(entry, fv, objectsToSkip)
-            }
-        } else {
-            o.getClass().getDeclaredFields().each {
-                Field field ->
-                if ((field.getModifiers() & Modifier.STATIC) || field.isSynthetic()) return;  //skip static
-                field.setAccessible true
-                def v = field.get(o);
-                fv.visit(o, field.name, v)
-                visitFields(v, fv, objectsToSkip)
-            }
-        }
-    }
-
-    public interface FieldVisitor {
-        /** Invoked by visitFields; fieldName will be null for collections */
-        public void visit(Object parent, String fieldName, Object value)
-    }
-
-    /**
-     * Iterates through two collections simultaneously, passing both args to code.
-     * 
-     * <pre>
-     * a = ['a','b']; b=[1,2];
-     * assert ['a1','b2'] == forboth(a,b) { x,y -> x+y }
-     * </pre>
-     */
-    public static Collection forBoth(Collection l1, Collection l2, Closure code) {
-        def result=[]
-        l1.eachWithIndex { a, i -> result.add( code.call(a, l2[i]) ) }
-        result
-    }
-
-    public static Collection forBothWithIndex(Collection l1, Collection l2, Closure code) {
-        def result=[]
-        l1.eachWithIndex { a, i -> result.add( code.call(a, l2[i], i) ) }
-        result
-    }
-
-    public static Collection forBoth(Object[] l1, Object[] l2, Closure code) {
-        def result=[]
-        l1.eachWithIndex { a, i -> result.add( code.call(a, l2[i]) ) }
-        result
-    }
-
-    public static Collection forBothWithIndex(Object[] l1, Object[] l2, Closure code) {
-        def result=[]
-        l1.eachWithIndex { a, i -> result.add( code.call(a, l2[i], i) ) }
-        result
-    }
-
-    /** return value used to indicate that there is no such field */
-    public static final Object NO_SUCH_FIELD = new Object();
-
-    /**
-     * Default field getter.
-     *
-     * Delegates to {@code object[field]} (which will invoke a getter if one exists, in groovy),
-     * unless field starts with {@literal @} in which case it looks up the actual java field (bypassing getter).
-     * <p>
-     * Can be extended as needed when passed to {@link #equals(Object, Object, Class, String[])}
-     */
-    public static final Closure DEFAULT_FIELD_GETTER = { Object object, Object field ->
-        try {
-            if ((field in String) && field.startsWith("@")) {
-                return object.@"${field.substring(1)}"
-            }
-            return object[field]
-        } catch (Exception e) {
-            return NO_SUCH_FIELD
-        }
-    }
-
-    /**
-     * Checks equality of o1 and o2 with respect to the named fields, optionally enforcing a common superclass
-     * and using a custom field-getter.
-     *
-     * Other types can be supplied if they are supported by {@code object[field]} (what the {@link #DEFAULT_FIELD_GETTER} does)
-     * or if the {@literal optionalGetter} handles it. Note that {@code object[field]} causes invocation of {@code object.getAt(field)}
-     * (which can be provided on the object for non-strings - this is preferred to an optionalGetter, generally)
-     * looking for {@code object.getXxx()}, where field is a string {@literal xxx}, then {@code object.xxx}.
-     * <p>
-     * One exception is that field names which start with {@literal @} get the field directly according to {@link #DEFAULT_FIELD_GETTER},
-     * but use with care on private fields, as they must be on the object and not a superclass, and with groovy properties
-     * (formerly known as package-private, i.e. with no access modifiers) because they become private fields.
-     * <p>
-     * For example
-     * <pre>
-     * public class Foo {
-     *   Object bar;
-     *   public boolean equals(Object other) { LangaugeUtils.equals(this, other, Foo.class, ["bar"]); }
-     *   public int hashCode() { LangaugeUtils.hashCode(this, ["bar"]); }
-     * }
-     * </pre>
-     *
-     * @param o1 one object to compare
-     * @param o2 other object to compare
-     * @param optionalCommonSuperClass if supplied, returns false unless both objects are instances of the given type;
-     *     (if not supplied it effectively does duck typing, returning false if any field is not present)
-     * @param optionalGetter if supplied, a closure which takes (object, field) and returns the value of field on object;
-     *  should return static {@link #NO_SUCH_FIELD} if none found;
-     *  recommended to delegate to {@link #DEFAULT_FIELD_GETTER} at least for strings (or for anything)
-     * @param fields typically a list of strings being names of fields on the class to compare
-     * @return true if the two objects are equal in all indicated fields, and conform to the optionalCommonSuperClass if supplied
-     */
-    public static boolean equals(Object o1, Object o2, Class<?> optionalCommonSuperClass=null, Closure optionalGetter=null, Iterable<Object> fieldNames) {
-        if (o1==null) return o2==null;
-        if (o2==null) return false;
-        if (optionalCommonSuperClass) {
-            if (!(o1 in optionalCommonSuperClass) || !(o2 in optionalCommonSuperClass)) return false
-        }
-        Closure get = optionalGetter ?: DEFAULT_FIELD_GETTER
-        for (it in fieldNames) {
-            def v1 = get.call(o1, it)
-            if (v1==NO_SUCH_FIELD) return false
-            if (v1!=get.call(o2, it)) return false
-        }
-        return true
-    }
-
-    public static boolean equals(Object o1, Object o2, Class<?> optionalCommonSuperClass=null, Closure optionalGetter=null, Object[] fieldNames) {
-        return equals(o1, o2, optionalCommonSuperClass, optionalGetter, Arrays.asList(fieldNames) )
-    }
-
-    /**
-     * Generates a hashcode for an object.
-     * 
-     * Similar to {@link com.google.common.base.Objects#hashCode()} but taking field <em>names</em> and an optional getter,
-     * with the same rich groovy semantics as described in {@link #equals(Object, Object, Class)}.
-     */
-    public static int hashCode(Object o, Closure optionalGetter=null, Collection<Object> fieldNames) {
-        if (o==null) return 0;
-        Closure get = optionalGetter ?: DEFAULT_FIELD_GETTER
-        int result = 1;
-        for (it in fieldNames) {
-            def v1 = get.call(o, it)
-            if (v1==NO_SUCH_FIELD)
-                throw new NoSuchFieldError("Cannot access $it on "+o.getClass());
-            result = 31 * result + (it == null ? 0 : it.hashCode());
-        }
-        result
-    }
-
-    public static int hashCode(Object o, Closure optionalGetter=null, Object[] fieldNames) {
-        hashCode(o, optionalGetter, Arrays.asList(fieldNames))
-    }
-    
-    /** Default String representation is simplified name of class, together with selected fields. */
-    public static String toString(Object o, Closure optionalGetter=null, Collection<? extends CharSequence> fieldNames) {
-        if (o==null) return null;
-        Closure get = optionalGetter ?: DEFAULT_FIELD_GETTER
-        
-        StringBuilder result = new StringBuilder();
-        result.append(o.getClass().getSimpleName());
-        if (result.length() == 0) result.append(o.getClass().getName());
-        List<Object> fieldVals = fieldNames.collect {
-                Object v = get.call(o, it);
-                return (v != null) ? it+"="+v : null;
-        }
-        result.append("[").append(Joiner.on(",").skipNulls().join(fieldVals)).append("]");
-        return result.toString();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/TimeExtras.groovy
----------------------------------------------------------------------
diff --git a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/TimeExtras.groovy b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/TimeExtras.groovy
deleted file mode 100644
index 9c6cdbd..0000000
--- a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/internal/TimeExtras.groovy
+++ /dev/null
@@ -1,83 +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.util.groovy.internal
-
-import groovy.time.TimeDuration
-
-import java.util.concurrent.TimeUnit
-
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-
-import org.apache.brooklyn.util.time.Time
-
-
-/**
- * Classloading this class will cause multiply/add to be made available on TimeDuration.
- * For example, I could write: 2*TimeUnit.MINUTES+5*TimeUnit.SECONDS.
- * 
- * That is why nothing seems to use this class, because the methods it defines are not 
- * on this class!
- * 
- * @author alex
- * 
- * @deprecated since 0.6.0 - just use brooklyn.util.time.Duration, simpler and easier to configure, and avoids language problems
- */
-@Deprecated
-class TimeExtras {
-    public static final Logger log = LoggerFactory.getLogger(TimeExtras.class);
-    
-    public static void init() {
-        Number.metaClass.multiply << { TimeUnit t -> new TimeDuration(t.toMillis(intValue())) }
-        Number.metaClass.multiply << { TimeDuration t -> t.multiply(doubleValue()) }
-        Integer.metaClass.multiply << { TimeUnit t -> new TimeDuration(t.toMillis(intValue())) }
-        
-        TimeDuration.metaClass.multiply << { Number n -> new TimeDuration( (int)(toMilliseconds()*n) ) }
-        TimeDuration.metaClass.constructor << { long millis ->
-            def shift = { int modulus -> int v=millis%modulus; millis/=modulus; v }
-            def l = [shift(1000), shift(60), shift(60), shift(24), (int)millis]
-            Collections.reverse(l)
-            l as TimeDuration
-        }
-    }
-    
-    static { init(); }
-    
-    /** creates a duration object
-     * <p>
-     * fix for irritating classloading/metaclass order 
-     * where an int may get constructed too early and not have the multiply syntax available
-     * (because grail is invoked?; if e.g. 5*SECONDS throws an error, try duration(5, SECONDS)  */ 
-    public static TimeDuration duration(int value, TimeUnit unit) {
-        return new TimeDuration(0, 0, 0, (int)unit.toMillis(value));
-    }
-    
-    public static final TimeDuration ONE_SECOND = duration(1, TimeUnit.SECONDS);
-    public static final TimeDuration FIVE_SECONDS = duration(5, TimeUnit.SECONDS);
-    public static final TimeDuration TEN_SECONDS = duration(10, TimeUnit.SECONDS);
-    public static final TimeDuration THIRTY_SECONDS = duration(30, TimeUnit.SECONDS);
-    public static final TimeDuration ONE_MINUTE = duration(1, TimeUnit.MINUTES);
-    public static final TimeDuration TWO_MINUTES = duration(2, TimeUnit.MINUTES);
-    public static final TimeDuration FIVE_MINUTES = duration(5, TimeUnit.MINUTES);
-
-    public static void sleep(TimeDuration duration) {
-        Time.sleep(duration.toMilliseconds());
-    }    
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/LanguageUtilsTest.groovy
----------------------------------------------------------------------
diff --git a/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/LanguageUtilsTest.groovy b/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/LanguageUtilsTest.groovy
new file mode 100644
index 0000000..961db5d
--- /dev/null
+++ b/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/LanguageUtilsTest.groovy
@@ -0,0 +1,152 @@
+/*
+ * 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.util.groovy;
+
+import static org.testng.Assert.*
+
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+import org.testng.annotations.Test
+import org.apache.brooklyn.util.groovy.LanguageUtils.FieldVisitor
+
+
+/**
+ * Test the operation of the {@link LanguageUtils} utilities.
+ */
+public class LanguageUtilsTest {
+    private static final Logger log = LoggerFactory.getLogger(LanguageUtilsTest.class)
+ 
+    @Test
+    public void testSetFieldsFromMap() {
+        A a = []
+        Map unused = LanguageUtils.setFieldsFromMap(a, [num:1,mun:2])
+        assertEquals(1, a.num);
+        assertEquals([mun:2], unused)
+    }
+    
+    @Test
+    public void testVisitingFieldsDeepNonLooping() {
+        BigUn b2 = new BigUn(name:"L'il Guy", num:10, dates:[ new Date() ])
+//        b2.dates = [ new Date() ] as Date[]
+        BigUn b1 = new BigUn(name:"Big Guy", num:40)
+        b1.child = b2;
+        b1.children += b2
+        b2.child = b1
+        
+        int sum = 0;
+        FieldVisitor numSummer = { parent, name, value -> if ("num"==name) sum+=value } as FieldVisitor
+        LanguageUtils.visitFields(b1, numSummer)
+        
+        assertEquals(50, sum) 
+    }
+    
+    private static class A {
+        int num;
+    }
+    
+    private static class BigUn {
+        String name;
+        int num;
+        BigUn child;
+        Set children = []
+        Date[] dates;
+    }
+
+    //test the default getter, and equals
+    static class TestingFieldA {
+        public int a = 6;
+        int getAt(A aa) { return aa.num * a; }
+        static A aa = [num:10];
+        int x = -1;
+    }
+    static class TestingFields extends TestingFieldA {
+        int b = 7;
+        int getB() { -7 }
+        public int c = 8;
+        int getD() { 9 }
+    }
+    @Test
+    public void testSomeGet() {
+        TestingFields tf = []
+        assertEquals( [6, -7, 7, 8, 9, 60],
+            ["a", "b", "@b", "c", "d", TestingFields.aa].collect {
+                LanguageUtils.DEFAULT_FIELD_GETTER.call(tf, it)
+            })
+    }
+    
+    @Test
+    public void testEquals() {
+        //basic
+        TestingFields t1 = [], t2 = []
+        assertTrue LanguageUtils.equals(t1, t2, null, ["a", "b"])
+        assertTrue LanguageUtils.equals(t1, t2, TestingFields, ["a", "b"])
+        assertFalse LanguageUtils.equals(t1, t2, String, ["a", "b"])
+        assertFalse LanguageUtils.equals(t1, t2, null, ["z"])
+        assertTrue LanguageUtils.equals(t1, t2, null, (["a", "b"] as String[]))
+        
+        //type hierarchy
+        TestingFieldA t1a = []
+        assertTrue LanguageUtils.equals(t1, t1a, null, "a")
+        assertTrue LanguageUtils.equals(t1, t1a, TestingFieldA, "a")
+        assertFalse LanguageUtils.equals(t1, t1a, TestingFields, "a")
+        assertFalse LanguageUtils.equals(t1, t1a, null, "a", "b")
+        t1.b = 0
+        assertTrue LanguageUtils.equals(t1, t1a, null, "a")
+        t1a.a = -6
+        assertFalse LanguageUtils.equals(t1, t1a, null, "a")
+        
+        //direct access to field
+        assertTrue LanguageUtils.equals(t1, t2, null, "b")
+        assertFalse LanguageUtils.equals(t1, t2, null, "@b")
+        assertTrue LanguageUtils.equals(t1, t2, null, "@a")
+        
+        //and complex field
+        assertTrue LanguageUtils.equals(t1, t2, null, TestingFields.aa)
+        //because we changed t1a.a, and getAt(A) refers to int a
+        assertFalse LanguageUtils.equals(t1, t1a, null, TestingFields.aa)
+        
+        //test it works with POJO objects (non-groovy)
+        assertTrue LanguageUtils.equals(new PojoTestingFields(1), new PojoTestingFields(1), null, "privateInt")
+        assertFalse LanguageUtils.equals(new PojoTestingFields(1), new PojoTestingFields(2), null, "privateInt")
+        
+        //and a tricky one, because x is a groovy property, it is _private_ so we cannot see it as a field wrt t1
+        assertFalse LanguageUtils.equals(t1, t1a, null, "@x")
+        //but in the context of t1a we can.. in short, be careful with fields
+        assertTrue LanguageUtils.equals(t1a, t1a, null, "@x")
+    }
+
+    @Test
+    public void testHashCode() {
+        //basic
+        TestingFields t1 = [], t2 = []
+        assertTrue LanguageUtils.hashCode(t1, ["a", "b"]) == LanguageUtils.hashCode(t2, ["a", "b"])
+        assertTrue LanguageUtils.hashCode(t1, ["a", "@b"]) == LanguageUtils.hashCode(t2, ["a", "@b"])
+        assertFalse LanguageUtils.hashCode(t1, ["a", "b"]) == LanguageUtils.hashCode(t2, ["a", "@b"])
+        t2.b = 0;
+        assertTrue LanguageUtils.hashCode(t1, ["a", "b"]) == LanguageUtils.hashCode(t2, ["a", "b"])
+        assertTrue LanguageUtils.hashCode(t1, ["a", "@b"]) == LanguageUtils.hashCode(t2, ["a", "@b"])
+        assertEquals 0, LanguageUtils.hashCode(null, ["a", "@b"])
+    }
+    
+    @Test
+    public void testToString() {
+        TestingFields t1 = [];
+        assertEquals(LanguageUtils.toString(t1, ["a", "b"]), "TestingFields[a=6,b=-7]");
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/PojoTestingFields.java
----------------------------------------------------------------------
diff --git a/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/PojoTestingFields.java b/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/PojoTestingFields.java
new file mode 100644
index 0000000..9bbc3fb
--- /dev/null
+++ b/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/PojoTestingFields.java
@@ -0,0 +1,28 @@
+/*
+ * 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.util.groovy;
+
+public class PojoTestingFields {
+    private final int privateInt;
+    
+    public PojoTestingFields(int privateInt) {
+        this.privateInt = privateInt;
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/TimeExtrasTest.groovy
----------------------------------------------------------------------
diff --git a/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/TimeExtrasTest.groovy b/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/TimeExtrasTest.groovy
new file mode 100644
index 0000000..11ae3d0
--- /dev/null
+++ b/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/TimeExtrasTest.groovy
@@ -0,0 +1,49 @@
+/*
+ * 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.util.groovy;
+
+import static java.util.concurrent.TimeUnit.*
+import static org.testng.Assert.*
+
+import groovy.time.TimeDuration
+
+import org.testng.annotations.BeforeMethod
+import org.testng.annotations.Test
+
+/**
+ * Test the operation of the {@link TimeExtras} class.
+ * 
+ * TODO clarify test purpose
+ */
+public class TimeExtrasTest {
+    @BeforeMethod
+    public void setUp() throws Exception {
+        TimeExtras.init();
+    }
+
+    @Test
+    public void testMultiplyTimeDurations() {
+        assertEquals(new TimeDuration(6).toMilliseconds(), (new TimeDuration(3)*2).toMilliseconds());
+    }
+
+    @Test
+    public void testAddTimeDurations() {
+        assertEquals(new TimeDuration(0,2,5,0).toMilliseconds(), (5*SECONDS + 2*MINUTES).toMilliseconds());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/LanguageUtilsTest.groovy
----------------------------------------------------------------------
diff --git a/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/LanguageUtilsTest.groovy b/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/LanguageUtilsTest.groovy
deleted file mode 100644
index 8c8d3d2..0000000
--- a/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/LanguageUtilsTest.groovy
+++ /dev/null
@@ -1,153 +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.util.groovy.internal;
-
-import static org.testng.Assert.*
-
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import org.testng.annotations.Test
-import org.apache.brooklyn.util.groovy.internal.LanguageUtils;
-import org.apache.brooklyn.util.groovy.internal.LanguageUtils.FieldVisitor
-
-
-/**
- * Test the operation of the {@link LanguageUtils} utilities.
- */
-public class LanguageUtilsTest {
-    private static final Logger log = LoggerFactory.getLogger(LanguageUtilsTest.class)
- 
-    @Test
-    public void testSetFieldsFromMap() {
-        A a = []
-        Map unused = LanguageUtils.setFieldsFromMap(a, [num:1,mun:2])
-        assertEquals(1, a.num);
-        assertEquals([mun:2], unused)
-    }
-    
-    @Test
-    public void testVisitingFieldsDeepNonLooping() {
-        BigUn b2 = new BigUn(name:"L'il Guy", num:10, dates:[ new Date() ])
-//        b2.dates = [ new Date() ] as Date[]
-        BigUn b1 = new BigUn(name:"Big Guy", num:40)
-        b1.child = b2;
-        b1.children += b2
-        b2.child = b1
-        
-        int sum = 0;
-        FieldVisitor numSummer = { parent, name, value -> if ("num"==name) sum+=value } as FieldVisitor
-        LanguageUtils.visitFields(b1, numSummer)
-        
-        assertEquals(50, sum) 
-    }
-    
-    private static class A {
-        int num;
-    }
-    
-    private static class BigUn {
-        String name;
-        int num;
-        BigUn child;
-        Set children = []
-        Date[] dates;
-    }
-
-    //test the default getter, and equals
-    static class TestingFieldA {
-        public int a = 6;
-        int getAt(A aa) { return aa.num * a; }
-        static A aa = [num:10];
-        int x = -1;
-    }
-    static class TestingFields extends TestingFieldA {
-        int b = 7;
-        int getB() { -7 }
-        public int c = 8;
-        int getD() { 9 }
-    }
-    @Test
-    public void testSomeGet() {
-        TestingFields tf = []
-        assertEquals( [6, -7, 7, 8, 9, 60],
-            ["a", "b", "@b", "c", "d", TestingFields.aa].collect {
-                LanguageUtils.DEFAULT_FIELD_GETTER.call(tf, it)
-            })
-    }
-    
-    @Test
-    public void testEquals() {
-        //basic
-        TestingFields t1 = [], t2 = []
-        assertTrue LanguageUtils.equals(t1, t2, null, ["a", "b"])
-        assertTrue LanguageUtils.equals(t1, t2, TestingFields, ["a", "b"])
-        assertFalse LanguageUtils.equals(t1, t2, String, ["a", "b"])
-        assertFalse LanguageUtils.equals(t1, t2, null, ["z"])
-        assertTrue LanguageUtils.equals(t1, t2, null, (["a", "b"] as String[]))
-        
-        //type hierarchy
-        TestingFieldA t1a = []
-        assertTrue LanguageUtils.equals(t1, t1a, null, "a")
-        assertTrue LanguageUtils.equals(t1, t1a, TestingFieldA, "a")
-        assertFalse LanguageUtils.equals(t1, t1a, TestingFields, "a")
-        assertFalse LanguageUtils.equals(t1, t1a, null, "a", "b")
-        t1.b = 0
-        assertTrue LanguageUtils.equals(t1, t1a, null, "a")
-        t1a.a = -6
-        assertFalse LanguageUtils.equals(t1, t1a, null, "a")
-        
-        //direct access to field
-        assertTrue LanguageUtils.equals(t1, t2, null, "b")
-        assertFalse LanguageUtils.equals(t1, t2, null, "@b")
-        assertTrue LanguageUtils.equals(t1, t2, null, "@a")
-        
-        //and complex field
-        assertTrue LanguageUtils.equals(t1, t2, null, TestingFields.aa)
-        //because we changed t1a.a, and getAt(A) refers to int a
-        assertFalse LanguageUtils.equals(t1, t1a, null, TestingFields.aa)
-        
-        //test it works with POJO objects (non-groovy)
-        assertTrue LanguageUtils.equals(new PojoTestingFields(1), new PojoTestingFields(1), null, "privateInt")
-        assertFalse LanguageUtils.equals(new PojoTestingFields(1), new PojoTestingFields(2), null, "privateInt")
-        
-        //and a tricky one, because x is a groovy property, it is _private_ so we cannot see it as a field wrt t1
-        assertFalse LanguageUtils.equals(t1, t1a, null, "@x")
-        //but in the context of t1a we can.. in short, be careful with fields
-        assertTrue LanguageUtils.equals(t1a, t1a, null, "@x")
-    }
-
-    @Test
-    public void testHashCode() {
-        //basic
-        TestingFields t1 = [], t2 = []
-        assertTrue LanguageUtils.hashCode(t1, ["a", "b"]) == LanguageUtils.hashCode(t2, ["a", "b"])
-        assertTrue LanguageUtils.hashCode(t1, ["a", "@b"]) == LanguageUtils.hashCode(t2, ["a", "@b"])
-        assertFalse LanguageUtils.hashCode(t1, ["a", "b"]) == LanguageUtils.hashCode(t2, ["a", "@b"])
-        t2.b = 0;
-        assertTrue LanguageUtils.hashCode(t1, ["a", "b"]) == LanguageUtils.hashCode(t2, ["a", "b"])
-        assertTrue LanguageUtils.hashCode(t1, ["a", "@b"]) == LanguageUtils.hashCode(t2, ["a", "@b"])
-        assertEquals 0, LanguageUtils.hashCode(null, ["a", "@b"])
-    }
-    
-    @Test
-    public void testToString() {
-        TestingFields t1 = [];
-        assertEquals(LanguageUtils.toString(t1, ["a", "b"]), "TestingFields[a=6,b=-7]");
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/PojoTestingFields.java
----------------------------------------------------------------------
diff --git a/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/PojoTestingFields.java b/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/PojoTestingFields.java
deleted file mode 100644
index ae5b5a0..0000000
--- a/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/PojoTestingFields.java
+++ /dev/null
@@ -1,28 +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.util.groovy.internal;
-
-public class PojoTestingFields {
-    private final int privateInt;
-    
-    public PojoTestingFields(int privateInt) {
-        this.privateInt = privateInt;
-    }
-}
-

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0eab0fa0/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/TimeExtrasTest.groovy
----------------------------------------------------------------------
diff --git a/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/TimeExtrasTest.groovy b/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/TimeExtrasTest.groovy
deleted file mode 100644
index a5aae79..0000000
--- a/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/internal/TimeExtrasTest.groovy
+++ /dev/null
@@ -1,51 +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.util.groovy.internal;
-
-import static java.util.concurrent.TimeUnit.*
-import static org.testng.Assert.*
-
-import org.apache.brooklyn.util.groovy.internal.TimeExtras;
-
-import groovy.time.TimeDuration
-
-import org.testng.annotations.BeforeMethod
-import org.testng.annotations.Test
-
-/**
- * Test the operation of the {@link TimeExtras} class.
- * 
- * TODO clarify test purpose
- */
-public class TimeExtrasTest {
-    @BeforeMethod
-    public void setUp() throws Exception {
-        TimeExtras.init();
-    }
-
-    @Test
-    public void testMultiplyTimeDurations() {
-        assertEquals(new TimeDuration(6).toMilliseconds(), (new TimeDuration(3)*2).toMilliseconds());
-    }
-
-    @Test
-    public void testAddTimeDurations() {
-        assertEquals(new TimeDuration(0,2,5,0).toMilliseconds(), (5*SECONDS + 2*MINUTES).toMilliseconds());
-    }
-}


[05/36] incubator-brooklyn git commit: Rename o.a.b.effector.core to o.a.b.core.effector

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/effector/core/EffectorSayHiTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/effector/core/EffectorSayHiTest.java b/core/src/test/java/org/apache/brooklyn/effector/core/EffectorSayHiTest.java
deleted file mode 100644
index 828cbd7..0000000
--- a/core/src/test/java/org/apache/brooklyn/effector/core/EffectorSayHiTest.java
+++ /dev/null
@@ -1,173 +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.effector.core;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertTrue;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.api.effector.ParameterType;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.entity.ImplementedBy;
-import org.apache.brooklyn.api.mgmt.ExecutionContext;
-import org.apache.brooklyn.api.mgmt.Task;
-import org.apache.brooklyn.core.annotation.EffectorParam;
-import org.apache.brooklyn.core.entity.AbstractEntity;
-import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
-import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.effector.core.MethodEffector;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.task.BasicTask;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-
-/**
- * Test the operation of the {@link Effector} implementations.
- *
- * TODO clarify test purpose
- */
-public class EffectorSayHiTest extends BrooklynAppUnitTestSupport {
-    
-    //TODO test edge/error conditions
-    //(missing parameters, wrong number of params, etc)
-
-    private static final Logger log = LoggerFactory.getLogger(EffectorSayHiTest.class);
-
-    private MyEntity e;
-
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        e = app.createAndManageChild(EntitySpec.create(MyEntity.class));
-    }
-
-    @Test
-    public void testFindEffectorMetaData() {
-        assertEquals("sayHi1", e.SAY_HI_1.getName());
-        assertEquals("says hello", e.SAY_HI_1.getDescription());
-        
-        assertEquals(ImmutableList.of("name", "greeting"), getParameterNames(e.SAY_HI_1));
-        assertEquals(MutableMap.of("name", null, "greeting", "what to say"), getParameterDescriptions(e.SAY_HI_1));
-    }
-
-    @Test
-    public void testFindTraitEffectors() {
-        assertEquals(ImmutableList.of("locations"), getParameterNames(Startable.START));
-    }
-
-    @Test
-    public void testInvokeEffectors1() throws Exception {
-        assertEquals("hi Bob", e.sayHi1("Bob", "hi"));
-
-        assertEquals("hi Bob", e.SAY_HI_1.call(e, ImmutableMap.of("name", "Bob", "greeting", "hi")) );
-        assertEquals("hi Bob", e.invoke(e.SAY_HI_1, ImmutableMap.of("name", "Bob", "greeting", "hi")).get() );
-        
-        // and with default greeting param value
-        assertEquals("hi Bob", e.SAY_HI_1.call(e, ImmutableMap.of("name", "Bob", "greeting", "hi")) );
-        assertEquals("hello Bob", e.invoke(e.SAY_HI_1, ImmutableMap.of("name", "Bob")).get() );
-    }
-
-    @Test
-    public void testCanRetrieveTaskForEffector() {
-        e.sayHi1("Bob", "hi");
-
-        Set<Task<?>> tasks = mgmt.getExecutionManager().getTasksWithAllTags(ImmutableList.of(
-                BrooklynTaskTags.tagForContextEntity(e),ManagementContextInternal.EFFECTOR_TAG));
-        assertEquals(tasks.size(), 1);
-        assertTrue(tasks.iterator().next().getDescription().contains("sayHi1"));
-    }
-
-    @Test
-    public void testDelegatedNestedEffectorNotRepresentedAsTask() {
-        e.delegateSayHi1("Bob", "hi");
-
-        Set<Task<?>> tasks = mgmt.getExecutionManager().getTasksWithAllTags(ImmutableList.of(
-                BrooklynTaskTags.tagForContextEntity(e),ManagementContextInternal.EFFECTOR_TAG));
-        assertEquals(tasks.size(), 1);
-        assertTrue(tasks.iterator().next().getDescription().contains("delegateSayHi1"));
-        assertFalse(tasks.iterator().next().getDescription().contains("sayHi1"));
-    }
-
-    @Test
-    public void testCanExcludeNonEffectorTasks() throws Exception {
-        ExecutionContext executionContext = mgmt.getExecutionContext(e);
-        executionContext.submit(new BasicTask<Void>(new Runnable() { public void run() {} }));
-
-        Set<Task<?>> effectTasks = mgmt.getExecutionManager().getTasksWithAllTags(ImmutableList.of(
-                BrooklynTaskTags.tagForContextEntity(e),ManagementContextInternal.EFFECTOR_TAG));
-        assertEquals(effectTasks.size(), 0);
-    }
-
-    public interface CanSayHi {
-        static MethodEffector<String> SAY_HI_1 = new MethodEffector<String>(CanSayHi.class, "sayHi1");
-        static MethodEffector<String> DELEGATE_SAY_HI_1 = new MethodEffector<String>(CanSayHi.class, "delegateSayHi1");
-    
-        @org.apache.brooklyn.core.annotation.Effector(description="says hello")
-        public String sayHi1(
-            @EffectorParam(name="name") String name,
-            @EffectorParam(name="greeting", defaultValue="hello", description="what to say") String greeting);
-        
-        @org.apache.brooklyn.core.annotation.Effector(description="delegate says hello")
-        public String delegateSayHi1(
-            @EffectorParam(name="name") String name,
-            @EffectorParam(name="greeting") String greeting);
-    }
-
-    @ImplementedBy(MyEntityImpl.class)
-    public interface MyEntity extends Entity, CanSayHi {
-    }
-    
-    public static class MyEntityImpl extends AbstractEntity implements MyEntity {
-        @Override
-        public String sayHi1(String name, String greeting) {
-            return greeting+" "+name;
-        }
-        @Override
-        public String delegateSayHi1(String name, String greeting) {
-            return sayHi1(name, greeting);
-        }
-    }
-    
-    private List<String> getParameterNames(Effector<?> effector) {
-        return ImmutableList.copyOf(getParameterDescriptions(effector).keySet());
-    }
-    
-    private Map<String, String> getParameterDescriptions(Effector<?> effector) {
-        Map<String,String> result = Maps.newLinkedHashMap();
-        for (ParameterType<?> parameter : effector.getParameters()) {
-            result.put(parameter.getName(), parameter.getDescription());
-        }
-        return result;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/effector/core/EffectorTaskTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/effector/core/EffectorTaskTest.java b/core/src/test/java/org/apache/brooklyn/effector/core/EffectorTaskTest.java
deleted file mode 100644
index 7d8a4f5..0000000
--- a/core/src/test/java/org/apache/brooklyn/effector/core/EffectorTaskTest.java
+++ /dev/null
@@ -1,437 +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.effector.core;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.mgmt.HasTaskChildren;
-import org.apache.brooklyn.api.mgmt.Task;
-import org.apache.brooklyn.core.entity.AbstractEntity;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.effector.core.EffectorBody;
-import org.apache.brooklyn.effector.core.EffectorTasks;
-import org.apache.brooklyn.effector.core.EffectorWithBody;
-import org.apache.brooklyn.effector.core.Effectors;
-import org.apache.brooklyn.effector.core.EffectorTasks.EffectorTaskFactory;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.core.task.DynamicSequentialTask;
-import org.apache.brooklyn.util.core.task.DynamicTasks;
-import org.apache.brooklyn.util.core.task.TaskBuilder;
-import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-
-public class EffectorTaskTest extends BrooklynAppUnitTestSupport {
-
-    // ----------- syntax 1 -- effector with body in a class
-    
-    public static final Effector<Integer> DOUBLE_1 = Effectors.effector(Integer.class, "double")
-            .description("doubles the given number")
-            .parameter(Integer.class, "numberToDouble")
-            .impl(new EffectorBody<Integer>() {
-                @Override
-                public Integer call(ConfigBag parameters) {
-                    // do a sanity check
-                    Assert.assertNotNull(entity());
-                    
-                    // finally double the input
-                    return 2*(Integer)parameters.getStringKey("numberToDouble");
-                }
-            })
-            .build();
-
-    public static class DoublingEntity extends AbstractEntity {
-        public static final Effector<Integer> DOUBLE = EffectorTaskTest.DOUBLE_1;
-    }
-
-    @Test
-    public void testSyntaxOneDouble1() throws Exception {
-        // just use "dynamic" support of effector
-        Assert.assertEquals(app.invoke(DOUBLE_1, MutableMap.of("numberToDouble", 3)).get(), (Integer)6);
-    }
-    
-    @Test
-    public void testSyntaxOneTaggedCorrectly() throws Exception {
-        Task<Integer> t = app.invoke(DOUBLE_1, MutableMap.of("numberToDouble", 3));
-        t.get();
-        checkTags(t, app, DOUBLE_1, false);
-    }
-    
-    @Test
-    // also assert it works when the effector is defined on an entity
-    public void testSimpleEffectorOnEntity() throws Exception {
-        Entity doubler = app.createAndManageChild(EntitySpec.create(Entity.class, DoublingEntity.class));
-        
-        Assert.assertEquals(doubler.invoke(DOUBLE_1, MutableMap.of("numberToDouble", 3)).get(), (Integer)6);
-    }
-
-    @Test
-    // also assert it works when an abstract effector name is passed in to the entity
-    public void testSimpleEffectorNameMatching() throws Exception {
-        Entity doubler = app.createAndManageChild(EntitySpec.create(Entity.class, DoublingEntity.class));
-        
-        Assert.assertEquals(doubler.invoke(Effectors.effector(Integer.class, "double").buildAbstract(), MutableMap.of("numberToDouble", 3)).get(), (Integer)6);
-    }
-
-
-    // ----------- syntax 2 -- effector with body built with fluent API
-    
-    public static EffectorTaskFactory<Integer> times(final EffectorTaskFactory<Integer> x, final int y) {
-        return new EffectorTaskFactory<Integer>() {
-            @Override
-            public Task<Integer> newTask(final Entity entity, final Effector<Integer> effector, final ConfigBag parameters) {
-                return TaskBuilder.<Integer>builder().name("times").body(new Callable<Integer>() { public Integer call() { 
-                    return DynamicTasks.get( x.newTask(entity, effector, parameters) )*y; 
-                } }).build();
-            }
-        };
-    }
-
-    public static final Effector<Integer> DOUBLE_2 = Effectors.effector(Integer.class, "double")
-            .description("doubles the given number")
-            .parameter(Integer.class, "numberToDouble")
-            .impl(times(EffectorTasks.parameter(Integer.class, "numberToDouble"), 2))
-            .build();
-
-    @Test
-    public void testSyntaxTwoDouble2() throws Exception {
-        Assert.assertEquals(app.invoke(DOUBLE_2, MutableMap.of("numberToDouble", 3)).get(), (Integer)6);
-    }
-
-    @Test
-    public void testEffectorImplTaggedCorrectly() throws Exception {
-        Task<Integer> t = app.invoke(DOUBLE_2, MutableMap.of("numberToDouble", 3));
-        t.get();
-        checkTags(t, app, DOUBLE_2, true);
-    }
-
-    public static final Effector<Integer> DOUBLE_CALL_ABSTRACT = Effectors.effector(Integer.class, "double_call")
-        .description("doubles the given number")
-        .parameter(Integer.class, "numberToDouble")
-        .buildAbstract();
-    public static final Effector<Integer> DOUBLE_CALL = Effectors.effector(DOUBLE_CALL_ABSTRACT)
-        .impl(new EffectorBody<Integer>() {
-            @Override
-            public Integer call(ConfigBag parameters) {
-                final Entity parent = entity();
-                final Entity child = Iterables.getOnlyElement(entity().getChildren());
-                
-                final Effector<Integer> DOUBLE_CHECK_ABSTRACT = Effectors.effector(Integer.class, "double_check")
-                    .description("doubles the given number and checks tags, assuming double exists as an effector here")
-                    .parameter(Integer.class, "numberToDouble")
-                    .buildAbstract();
-                Effector<Integer> DOUBLE_CHECK = Effectors.effector(DOUBLE_CHECK_ABSTRACT)
-                    .impl(new EffectorBody<Integer>() {
-                        @Override
-                        public Integer call(ConfigBag parameters) {
-                            Assert.assertTrue(BrooklynTaskTags.isInEffectorTask(Tasks.current(), child, null, false));
-                            Assert.assertTrue(BrooklynTaskTags.isInEffectorTask(Tasks.current(), child, DOUBLE_CHECK_ABSTRACT, false));
-                            Assert.assertFalse(BrooklynTaskTags.isInEffectorTask(Tasks.current(), child, DOUBLE_1, false));
-                            Assert.assertTrue(BrooklynTaskTags.isInEffectorTask(Tasks.current(), parent, null, true));
-                            Assert.assertFalse(BrooklynTaskTags.isInEffectorTask(Tasks.current(), parent, null, false));
-                            Assert.assertTrue(BrooklynTaskTags.isInEffectorTask(Tasks.current(), parent, DOUBLE_CALL_ABSTRACT, true));
-                            Assert.assertFalse(BrooklynTaskTags.isInEffectorTask(Tasks.current(), parent, DOUBLE_1, true));
-                            
-                            return entity().invoke(DOUBLE_1, parameters.getAllConfig()).getUnchecked();
-                        }
-                    }).build();
-
-                return child.invoke(DOUBLE_CHECK, parameters.getAllConfig()).getUnchecked();
-            }
-        }).build();
-
-
-    @Test
-    // also assert it works when the effector is defined on an entity
-    public void testNestedEffectorTag() throws Exception {
-        app.createAndManageChild(EntitySpec.create(Entity.class, DoublingEntity.class));
-        Assert.assertEquals(app.invoke(DOUBLE_CALL, MutableMap.of("numberToDouble", 3)).get(), (Integer)6);
-    }
-
-
-    private void checkTags(Task<Integer> t, Entity entity, Effector<?> eff, boolean shouldHaveChild) {
-        Assert.assertEquals(BrooklynTaskTags.getContextEntity(t), app);
-        Assert.assertTrue(t.getTags().contains(BrooklynTaskTags.EFFECTOR_TAG), "missing effector tag; had: "+t.getTags());
-        Assert.assertTrue(t.getDescription().contains(eff.getName()), "description missing effector name: "+t.getDescription());
-        Assert.assertTrue(BrooklynTaskTags.isInEffectorTask(t, entity, eff, false));
-        Assert.assertTrue(BrooklynTaskTags.isInEffectorTask(t, null, null, false));
-        Assert.assertFalse(BrooklynTaskTags.isInEffectorTask(t, entity, Startable.START, false));
-        
-        if (shouldHaveChild) {
-            Task<?> subtask = ((HasTaskChildren)t).getChildren().iterator().next();
-            Assert.assertTrue(BrooklynTaskTags.isInEffectorTask(subtask, entity, eff, false));
-            Assert.assertTrue(BrooklynTaskTags.isInEffectorTask(subtask, null, null, false));
-        }
-    }
-
-    // TEST parameter task missing
-    
-    // ----------------- syntax for more complex -- an effector using subtasks
-    
-    public static Task<Integer> add(final int x, final int y) {
-        return TaskBuilder.<Integer>builder().name("add").body(new Callable<Integer>() { public Integer call() { return x+y; } }).build();
-    }
-
-    public static Task<Integer> add(final Task<Integer> x, final int y) {
-        return TaskBuilder.<Integer>builder().name("add").body(new Callable<Integer>() { public Integer call() { return DynamicTasks.get(x)+y; } }).build();
-    }
-
-    public static Task<Integer> addBasic(final Task<Integer> x, final int y) {
-        return TaskBuilder.<Integer>builder().name("add (not dynamic)").dynamic(false).body(new Callable<Integer>() { public Integer call() {
-            Preconditions.checkState(x.isSubmitted()); 
-            return x.getUnchecked()+y; 
-        } }).build();
-    }
-
-    public static Task<Integer> times(final int x, final int y) {
-        return TaskBuilder.<Integer>builder().name("times").body(new Callable<Integer>() { public Integer call() { return x*y; } }).build();
-    }
-
-    public static Task<Integer> times(final Task<Integer> x, final int y) {
-        return TaskBuilder.<Integer>builder().name("times").body(new Callable<Integer>() { public Integer call() { return DynamicTasks.get(x)*y; } }).build();
-    }
-    
-    public static final Effector<Integer> TWO_X_PLUS_ONE = Effectors.effector(Integer.class, "twoXPlusOne")
-            .description("doubles the given number and adds one")
-            .parameter(Integer.class, "numberToStartWith")
-            .impl(new EffectorBody<Integer>() {
-                public Integer call(ConfigBag parameters) {
-                    int input = (Integer)parameters.getStringKey("numberToStartWith");
-                    queue( add(times(input, 2), 1) );
-                    return last(Integer.class);
-                }
-            })
-            .build();
-
-    public static final Effector<Integer> TWO_X_PLUS_ONE_BASIC = Effectors.effector(Integer.class, "twoXPlusOne_Basic")
-            .description("doubles the given number and adds one, as a basic task")
-            .parameter(Integer.class, "numberToStartWith")
-            .impl(new EffectorBody<Integer>() {
-                public Integer call(ConfigBag parameters) {
-                    int input = (Integer)parameters.getStringKey("numberToStartWith");
-                    // note the subtasks must be queued explicitly with a basic task
-                    // (but with the DynamicSequentialTask they can be resolved by the task itself; see above)
-                    Task<Integer> product = queue(times(input, 2));
-                    queue( addBasic(product, 1) );
-                    return last(Integer.class);
-                }
-            })
-            .build();
-
-    // TODO a chaining style approach
-    
-    public static class Txp1Entity extends AbstractEntity {
-        public static final Effector<Integer> TWO_X_P_1 = EffectorTaskTest.TWO_X_PLUS_ONE;
-    }
-
-    /** the composed effector should allow us to inspect its children */
-    @Test
-    public void testComposedEffector() throws Exception {
-        Entity txp1 = app.createAndManageChild(EntitySpec.create(Entity.class, Txp1Entity.class));
-        
-        Task<Integer> e = txp1.invoke(TWO_X_PLUS_ONE, MutableMap.of("numberToStartWith", 3));
-        Assert.assertTrue(e instanceof DynamicSequentialTask);
-        Assert.assertEquals(e.get(), (Integer)7);
-        Assert.assertEquals( Iterables.size( ((HasTaskChildren)e).getChildren() ), 1);
-        Task<?> child = ((HasTaskChildren)e).getChildren().iterator().next();
-        Assert.assertEquals( Iterables.size( ((HasTaskChildren)child).getChildren() ), 1);
-    }
-
-    /** the composed effector should allow us to inspect its children */
-    @Test
-    public void testComposedEffectorBasic() throws Exception {
-        Entity txp1 = app.createAndManageChild(EntitySpec.create(Entity.class, Txp1Entity.class));
-        
-        Task<Integer> e = txp1.invoke(TWO_X_PLUS_ONE_BASIC, MutableMap.of("numberToStartWith", 3));
-        Assert.assertTrue(e instanceof DynamicSequentialTask);
-        Assert.assertEquals(e.get(), (Integer)7);
-        Assert.assertEquals( Iterables.size( ((HasTaskChildren)e).getChildren() ), 2);
-    }
-
-    // --------- defining 
-    
-    @Test
-    public void testEffectorWithBodyWorksEvenIfNotOnEntity() throws Exception {
-        Entity doubler = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        
-        Assert.assertEquals(doubler.invoke(DOUBLE_1, MutableMap.of("numberToDouble", 3)).get(), (Integer)6);
-    }
-
-    public static final Effector<Integer> DOUBLE_BODYLESS = Effectors.effector(Integer.class, "double")
-            .description("doubles the given number")
-            .parameter(Integer.class, "numberToDouble")
-            .buildAbstract();
-    
-    @Test
-    public void testEffectorWithoutBodyFails() throws Exception {
-        Entity doubler = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        
-        boolean failed = false;
-        try {
-            doubler.invoke(DOUBLE_BODYLESS, MutableMap.of("numberToDouble", 3));
-        } catch (Exception e) {
-            failed = true;
-        }
-        if (!failed) Assert.fail("doubling should have failed because it had no body");
-    }
-
-    @Test
-    public void testEffectorBodyAdded() throws Exception {
-        EntityInternal doubler = (EntityInternal) app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        
-        // not yet present
-        Assert.assertNull( doubler.getEffector("double") );
-        
-        // add it
-        doubler.getMutableEntityType().addEffector(DOUBLE_BODYLESS, new EffectorBody<Integer>() {
-            @Override
-            public Integer call(ConfigBag parameters) {
-                int input = (Integer)parameters.getStringKey("numberToDouble");
-                return queue(times(input, 2)).getUnchecked();            
-            }
-        });
-        // now it is present
-        Assert.assertNotNull( doubler.getEffector("double") );
-        
-        Assert.assertEquals(doubler.invoke(DOUBLE_BODYLESS, MutableMap.of("numberToDouble", 3)).get(), (Integer)6);
-    }
-
-    @Test
-    public void testEffectorBodyAddedImplicitlyButBodylessSignatureInvoked() throws Exception {
-        EntityInternal doubler = (EntityInternal) app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        
-        // add it
-        doubler.getMutableEntityType().addEffector(DOUBLE_1);
-
-        // invoke it, but using something with equivalent name (and signature -- though only name is used currently)
-        // ensures that the call picks up the body by looking in the actual entity
-        Assert.assertEquals(doubler.invoke(DOUBLE_BODYLESS, MutableMap.of("numberToDouble", 3)).get(), (Integer)6);
-    }
- 
-    @Test(dependsOnMethods={"testEffectorBodyAdded"})
-    public void testEntityNotPermanentlyChanged() throws Exception {
-        EntityInternal doubler = (EntityInternal) app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        // ensures that independent creations of the class previously modified do not have this effector 
-        Assert.assertNull( doubler.getEffector("double") );
-   }
-    
-    // --- overriding by using statics ---------
-
-    public static class BadDoublingEntity extends DoublingEntity {
-        public static final Effector<Integer> DOUBLE = Effectors.effector(DoublingEntity.DOUBLE).
-                impl( ((EffectorWithBody<Integer>)TWO_X_PLUS_ONE).getBody() ).build();
-    }
-
-    @Test
-    // also assert it works when the entity is defined on an entity
-    public void testOverriddenEffectorOnEntity() throws Exception {
-        Entity doubler = app.createAndManageChild(EntitySpec.create(Entity.class, BadDoublingEntity.class));
-        
-        Assert.assertEquals(doubler.invoke(DoublingEntity.DOUBLE, MutableMap.of("numberToDouble", 3, "numberToStartWith", 3)).get(), (Integer)7);
-    }
-    
-    public static final Effector<Void> DUMMY = Effectors.effector(Void.class, "dummy")
-            .impl(new EffectorBody<Void>() {
-                @Override
-                public Void call(ConfigBag parameters) {
-                    return null;
-                }
-            })
-            .build();
-    
-    public static final Effector<Void> STALL = Effectors.effector(Void.class, "stall")
-            .parameter(AtomicBoolean.class, "lock")
-            .impl(new EffectorBody<Void>() {
-                @Override
-                public Void call(ConfigBag parameters) {
-                    AtomicBoolean lock = (AtomicBoolean)parameters.getStringKey("lock");
-                    synchronized(lock) {
-                        if (!lock.get()) {
-                            try {
-                                lock.wait();
-                            } catch (InterruptedException e) {
-                                Exceptions.propagate(e);
-                            }
-                        }
-                    }
-                    return null;
-                }
-            })
-            .build();
-
-    public static final Effector<Void> CONTEXT = Effectors.effector(Void.class, "stall_caller")
-            .parameter(AtomicBoolean.class, "lock")
-            .impl(new EffectorBody<Void>() {
-                @Override
-                public Void call(ConfigBag parameters) {
-                    Entity child = Iterables.getOnlyElement(entity().getChildren());
-                    AtomicBoolean lock = new AtomicBoolean();
-                    Task<Void> dummyTask = null;
-
-                    try {
-                        // Queue a (DST secondary) task which waits until notified, so that tasks queued later will get blocked
-                        queue(Effectors.invocation(entity(), STALL, ImmutableMap.of("lock", lock)));
-    
-                        // Start a new task - submitted directly to child's ExecutionContext, as well as added as a
-                        // DST secondary of the current effector.
-                        dummyTask = child.invoke(DUMMY, ImmutableMap.<String, Object>of());
-                        dummyTask.getUnchecked();
-
-                        // Execution completed in the child's ExecutionContext, but still queued as a secondary.
-                        // Destroy the child entity so that no subsequent tasks can be executed in its context.
-                        Entities.destroy(child);
-                    } finally {
-                        // Let STALL complete
-                        synchronized(lock) {
-                            lock.set(true);
-                            lock.notifyAll();
-                        }
-                        // At this point DUMMY will be unblocked and the DST will try to execute it as a secondary.
-                        // Submission will be ignored because DUMMY already executed.
-                        // If it's not ignored then submission will fail because entity is already unmanaged.
-                    }
-                    return null;
-                }
-            })
-            .build();
-    
-
-    @Test
-    public void testNestedEffectorExecutedAsSecondaryTask() throws Exception {
-        app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        Task<Void> effTask = app.invoke(CONTEXT, ImmutableMap.<String, Object>of());
-        effTask.get();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/effector/core/ssh/SshEffectorTasksTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/effector/core/ssh/SshEffectorTasksTest.java b/core/src/test/java/org/apache/brooklyn/effector/core/ssh/SshEffectorTasksTest.java
deleted file mode 100644
index 597d267..0000000
--- a/core/src/test/java/org/apache/brooklyn/effector/core/ssh/SshEffectorTasksTest.java
+++ /dev/null
@@ -1,264 +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.effector.core.ssh;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Arrays;
-
-import org.apache.brooklyn.api.location.LocationSpec;
-import org.apache.brooklyn.api.mgmt.ManagementContext;
-import org.apache.brooklyn.api.mgmt.TaskAdaptable;
-import org.apache.brooklyn.api.mgmt.TaskFactory;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
-import org.apache.brooklyn.util.core.task.ssh.SshFetchTaskWrapper;
-import org.apache.brooklyn.util.core.task.ssh.SshPutTaskWrapper;
-import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
-import org.apache.brooklyn.util.exceptions.PropagatedRuntimeException;
-import org.apache.brooklyn.util.net.Urls;
-import org.apache.commons.io.FileUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
-import org.apache.brooklyn.location.ssh.SshMachineLocation;
-
-import com.google.common.io.Files;
-
-public class SshEffectorTasksTest {
-
-    private static final Logger log = LoggerFactory.getLogger(SshEffectorTasksTest.class);
-    
-    TestApplication app;
-    ManagementContext mgmt;
-    SshMachineLocation host;
-    File tempDir;
-    
-    boolean failureExpected;
-
-    @BeforeMethod(alwaysRun=true)
-    public void setup() throws Exception {
-        app = TestApplication.Factory.newManagedInstanceForTests();
-        mgmt = app.getManagementContext();
-        
-        LocalhostMachineProvisioningLocation lhc = mgmt.getLocationManager().createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class));
-        host = lhc.obtain();
-        app.start(Arrays.asList(host));
-        clearExpectedFailure();
-        tempDir = Files.createTempDir();
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        if (mgmt != null) Entities.destroyAll(mgmt);
-        mgmt = null;
-        FileUtils.deleteDirectory(tempDir);
-        checkExpectedFailure();
-    }
-
-    protected void checkExpectedFailure() {
-        if (failureExpected) {
-            clearExpectedFailure();
-            Assert.fail("Test should have thrown an exception but it did not.");
-        }
-    }
-    
-    protected void clearExpectedFailure() {
-        failureExpected = false;
-    }
-
-    protected void setExpectingFailure() {
-        failureExpected = true;
-    }
-    
-    public <T extends TaskAdaptable<?>> T submit(final TaskFactory<T> taskFactory) {
-        return Entities.submit(app, taskFactory);
-    }
-    
-    // ------------------- basic ssh
-    
-    @Test(groups="Integration")
-    public void testSshEchoHello() {
-        ProcessTaskWrapper<Integer> t = submit(SshEffectorTasks.ssh("sleep 1 ; echo hello world"));
-        Assert.assertFalse(t.isDone());
-        Assert.assertEquals(t.get(), (Integer)0);
-        Assert.assertEquals(t.getTask().getUnchecked(), (Integer)0);
-        Assert.assertEquals(t.getStdout().trim(), "hello world");
-    }
-
-    @Test(groups="Integration")
-    public void testSshPut() throws IOException {
-        String fn = Urls.mergePaths(tempDir.getPath(), "f1");
-        SshPutTaskWrapper t = submit(SshEffectorTasks.put(fn).contents("hello world"));
-        t.block();
-        Assert.assertEquals(FileUtils.readFileToString(new File(fn)), "hello world");
-        // and make sure this doesn't throw
-        Assert.assertTrue(t.isDone());
-        Assert.assertTrue(t.isSuccessful());
-        Assert.assertEquals(t.get(), null);
-        Assert.assertEquals(t.getExitCode(), (Integer)0);
-    }
-
-    @Test(groups="Integration")
-    public void testSshFetch() throws IOException {
-        String fn = Urls.mergePaths(tempDir.getPath(), "f2");
-        FileUtils.write(new File(fn), "hello fetched world");
-        
-        SshFetchTaskWrapper t = submit(SshEffectorTasks.fetch(fn));
-        t.block();
-        
-        Assert.assertTrue(t.isDone());
-        Assert.assertEquals(t.get(), "hello fetched world");
-    }
-
-    // ----------------- pid stuff
-    
-    @Test(groups="Integration")
-    public void testNonRunningPid() {
-        ProcessTaskWrapper<Integer> t = submit(SshEffectorTasks.codePidRunning(99999));
-        Assert.assertNotEquals(t.getTask().getUnchecked(), (Integer)0);
-        Assert.assertNotEquals(t.getExitCode(), (Integer)0);
-        ProcessTaskWrapper<Boolean> t2 = submit(SshEffectorTasks.isPidRunning(99999));
-        Assert.assertFalse(t2.getTask().getUnchecked());
-    }
-
-    @Test(groups="Integration")
-    public void testNonRunningPidRequired() {
-        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidRunning(99999));
-        setExpectingFailure();
-        try {
-            t.getTask().getUnchecked();
-        } catch (Exception e) {
-            log.info("The error if required PID is not found is: "+e);
-            clearExpectedFailure();
-            Assert.assertTrue(e.toString().contains("Process with PID"), "Expected nice clue in error but got: "+e);
-        }
-        checkExpectedFailure();
-    }
-
-    public static Integer getMyPid() {
-        try {
-            java.lang.management.RuntimeMXBean runtime = 
-                    java.lang.management.ManagementFactory.getRuntimeMXBean();
-            java.lang.reflect.Field jvm = runtime.getClass().getDeclaredField("jvm");
-            jvm.setAccessible(true);
-//            sun.management.VMManagement mgmt = (sun.management.VMManagement) jvm.get(runtime);
-            Object mgmt = jvm.get(runtime);
-            java.lang.reflect.Method pid_method =  
-                    mgmt.getClass().getDeclaredMethod("getProcessId");
-            pid_method.setAccessible(true);
-
-            return (Integer) pid_method.invoke(mgmt);
-        } catch (Exception e) {
-            throw new PropagatedRuntimeException("Test depends on (fragile) getMyPid method which does not work here", e);
-        }
-    }
-
-    @Test(groups="Integration")
-    public void testRunningPid() {
-        ProcessTaskWrapper<Integer> t = submit(SshEffectorTasks.codePidRunning(getMyPid()));
-        Assert.assertEquals(t.getTask().getUnchecked(), (Integer)0);
-        ProcessTaskWrapper<Boolean> t2 = submit(SshEffectorTasks.isPidRunning(getMyPid()));
-        Assert.assertTrue(t2.getTask().getUnchecked());
-    }
-
-    @Test(groups="Integration")
-    public void testRunningPidFromFile() throws IOException {
-        File f = File.createTempFile("testBrooklynPid", ".pid");
-        Files.write( (""+getMyPid()).getBytes(), f );
-        ProcessTaskWrapper<Integer> t = submit(SshEffectorTasks.codePidFromFileRunning(f.getPath()));
-        Assert.assertEquals(t.getTask().getUnchecked(), (Integer)0);
-        ProcessTaskWrapper<Boolean> t2 = submit(SshEffectorTasks.isPidFromFileRunning(f.getPath()));
-        Assert.assertTrue(t2.getTask().getUnchecked());
-    }
-
-    @Test(groups="Integration")
-    public void testRequirePidFromFileOnFailure() throws IOException {
-        File f = File.createTempFile("testBrooklynPid", ".pid");
-        Files.write( "99999".getBytes(), f );
-        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidFromFileRunning(f.getPath()));
-        
-        setExpectingFailure();
-        try {
-            t.getTask().getUnchecked();
-        } catch (Exception e) {
-            log.info("The error if required PID is not found is: "+e);
-            clearExpectedFailure();
-            Assert.assertTrue(e.toString().contains("Process with PID"), "Expected nice clue in error but got: "+e);
-            Assert.assertEquals(t.getExitCode(), (Integer)1);
-        }
-        checkExpectedFailure();
-    }
-
-    @Test(groups="Integration")
-    public void testRequirePidFromFileOnFailureNoSuchFile() throws IOException {
-        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidFromFileRunning("/path/does/not/exist/SADVQW"));
-        
-        setExpectingFailure();
-        try {
-            t.getTask().getUnchecked();
-        } catch (Exception e) {
-            log.info("The error if required PID is not found is: "+e);
-            clearExpectedFailure();
-            Assert.assertTrue(e.toString().contains("Process with PID"), "Expected nice clue in error but got: "+e);
-            Assert.assertEquals(t.getExitCode(), (Integer)1);
-        }
-        checkExpectedFailure();
-    }
-
-    @Test(groups="Integration")
-    public void testRequirePidFromFileOnFailureTooManyFiles() throws IOException {
-        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidFromFileRunning("/*"));
-        
-        setExpectingFailure();
-        try {
-            t.getTask().getUnchecked();
-        } catch (Exception e) {
-            log.info("The error if required PID is not found is: "+e);
-            clearExpectedFailure();
-            Assert.assertTrue(e.toString().contains("Process with PID"), "Expected nice clue in error but got: "+e);
-            Assert.assertEquals(t.getExitCode(), (Integer)2);
-        }
-        checkExpectedFailure();
-    }
-
-    @Test(groups="Integration")
-    public void testRequirePidFromFileOnSuccess() throws IOException {
-        File f = File.createTempFile("testBrooklynPid", ".pid");
-        Files.write( (""+getMyPid()).getBytes(), f );
-        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidFromFileRunning(f.getPath()));
-        
-        t.getTask().getUnchecked();
-    }
-
-    @Test(groups="Integration")
-    public void testRequirePidFromFileOnSuccessAcceptsWildcards() throws IOException {
-        File f = File.createTempFile("testBrooklynPid", ".pid");
-        Files.write( (""+getMyPid()).getBytes(), f );
-        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidFromFileRunning(f.getPath()+"*"));
-        
-        t.getTask().getUnchecked();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/location/ssh/SshMachineLocationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/location/ssh/SshMachineLocationTest.java b/core/src/test/java/org/apache/brooklyn/location/ssh/SshMachineLocationTest.java
index dec55ec..1aa71f1 100644
--- a/core/src/test/java/org/apache/brooklyn/location/ssh/SshMachineLocationTest.java
+++ b/core/src/test/java/org/apache/brooklyn/location/ssh/SshMachineLocationTest.java
@@ -43,6 +43,9 @@ import org.apache.brooklyn.api.location.MachineDetails;
 import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.api.location.PortRange;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.core.effector.EffectorBody;
+import org.apache.brooklyn.core.effector.EffectorTaskTest;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
@@ -54,9 +57,6 @@ import org.apache.brooklyn.core.location.Machines;
 import org.apache.brooklyn.core.location.PortRanges;
 import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.apache.brooklyn.effector.core.EffectorBody;
-import org.apache.brooklyn.effector.core.EffectorTaskTest;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.collections.MutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/util/core/task/ssh/SshTasksTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/task/ssh/SshTasksTest.java b/core/src/test/java/org/apache/brooklyn/util/core/task/ssh/SshTasksTest.java
index 6b6c0b1..cb0e50c 100644
--- a/core/src/test/java/org/apache/brooklyn/util/core/task/ssh/SshTasksTest.java
+++ b/core/src/test/java/org/apache/brooklyn/util/core/task/ssh/SshTasksTest.java
@@ -23,10 +23,10 @@ import java.io.IOException;
 
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasksTest;
 import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasksTest;
 import org.apache.commons.io.FileUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/CumulusRDFApplication.java
----------------------------------------------------------------------
diff --git a/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/CumulusRDFApplication.java b/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/CumulusRDFApplication.java
index e7e1df9..bc3671f 100644
--- a/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/CumulusRDFApplication.java
+++ b/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/CumulusRDFApplication.java
@@ -36,6 +36,9 @@ 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.effector.EffectorBody;
+import org.apache.brooklyn.core.effector.Effectors;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.AbstractApplication;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
@@ -44,9 +47,6 @@ import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.location.PortRanges;
-import org.apache.brooklyn.effector.core.EffectorBody;
-import org.apache.brooklyn.effector.core.Effectors;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.java.UsesJava;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.entity.nosql.cassandra.CassandraDatacenter;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/policy/src/main/java/org/apache/brooklyn/policy/loadbalancing/Movable.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/loadbalancing/Movable.java b/policy/src/main/java/org/apache/brooklyn/policy/loadbalancing/Movable.java
index 1c6e75a..bec64cc 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/loadbalancing/Movable.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/loadbalancing/Movable.java
@@ -23,7 +23,7 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.annotation.EffectorParam;
 import org.apache.brooklyn.core.config.BasicConfigKey;
-import org.apache.brooklyn.effector.core.MethodEffector;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/policy/src/test/java/org/apache/brooklyn/policy/loadbalancing/MockContainerEntity.java
----------------------------------------------------------------------
diff --git a/policy/src/test/java/org/apache/brooklyn/policy/loadbalancing/MockContainerEntity.java b/policy/src/test/java/org/apache/brooklyn/policy/loadbalancing/MockContainerEntity.java
index b11640d..e5b826d 100644
--- a/policy/src/test/java/org/apache/brooklyn/policy/loadbalancing/MockContainerEntity.java
+++ b/policy/src/test/java/org/apache/brooklyn/policy/loadbalancing/MockContainerEntity.java
@@ -26,8 +26,8 @@ import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.annotation.EffectorParam;
 import org.apache.brooklyn.core.config.BasicConfigKey;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.effector.core.MethodEffector;
 import org.apache.brooklyn.entity.group.AbstractGroup;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeSaltImpl.java
----------------------------------------------------------------------
diff --git a/sandbox/extra/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeSaltImpl.java b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeSaltImpl.java
index 58ec93f..ace9a62 100644
--- a/sandbox/extra/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeSaltImpl.java
+++ b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeSaltImpl.java
@@ -33,13 +33,13 @@ import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.api.effector.Effector;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.EffectorBody;
+import org.apache.brooklyn.core.effector.Effectors;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.entity.stock.EffectorStartableImpl;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.database.postgresql.PostgreSqlNode;
-import org.apache.brooklyn.effector.core.EffectorBody;
-import org.apache.brooklyn.effector.core.Effectors;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.sensor.core.DependentConfiguration;
 import org.apache.brooklyn.sensor.feed.ssh.SshFeed;
 import org.apache.brooklyn.sensor.feed.ssh.SshPollConfig;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltLifecycleEffectorTasks.java
----------------------------------------------------------------------
diff --git a/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltLifecycleEffectorTasks.java b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltLifecycleEffectorTasks.java
index 198d139..5a404a1 100644
--- a/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltLifecycleEffectorTasks.java
+++ b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltLifecycleEffectorTasks.java
@@ -20,10 +20,10 @@ package org.apache.brooklyn.entity.salt;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.MachineLocation;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.server.BrooklynServerConfig;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
 import org.apache.brooklyn.util.core.task.Tasks;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltTasks.java
----------------------------------------------------------------------
diff --git a/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltTasks.java b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltTasks.java
index c00e48b..d6bacfa 100644
--- a/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltTasks.java
+++ b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltTasks.java
@@ -28,14 +28,13 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.mgmt.TaskFactory;
+import org.apache.brooklyn.core.effector.EffectorTasks;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
 import org.apache.brooklyn.util.core.task.Tasks;
 import org.apache.brooklyn.util.core.text.TemplateProcessor;
-
-import org.apache.brooklyn.effector.core.EffectorTasks;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.net.Urls;
 import org.apache.brooklyn.util.ssh.BashCommands;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/sandbox/extra/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSaltLiveTest.java
----------------------------------------------------------------------
diff --git a/sandbox/extra/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSaltLiveTest.java b/sandbox/extra/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSaltLiveTest.java
index b25c92f..8dfaaeb 100644
--- a/sandbox/extra/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSaltLiveTest.java
+++ b/sandbox/extra/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSaltLiveTest.java
@@ -22,6 +22,8 @@ import java.util.Random;
 
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.PortRange;
+import org.apache.brooklyn.core.effector.EffectorTasks;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.PortRanges;
 import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
@@ -38,8 +40,6 @@ import org.testng.annotations.Test;
 import org.apache.brooklyn.entity.database.VogellaExampleAccess;
 import org.apache.brooklyn.entity.database.postgresql.PostgreSqlIntegrationTest;
 import org.apache.brooklyn.entity.database.postgresql.PostgreSqlNode;
-import org.apache.brooklyn.effector.core.EffectorTasks;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.time.Duration;
 
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynCluster.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynCluster.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynCluster.java
index daf7369..f00b4db 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynCluster.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynCluster.java
@@ -26,7 +26,7 @@ import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.effector.core.Effectors;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.entity.brooklynnode.effector.BrooklynNodeUpgradeEffectorBody;
 import org.apache.brooklyn.entity.group.DynamicCluster;
 import org.apache.brooklyn.sensor.core.Sensors;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java
index 1ca17fc..0a99d1f 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java
@@ -25,13 +25,13 @@ import java.util.concurrent.Callable;
 import javax.annotation.Nullable;
 
 import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.core.effector.EffectorBody;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityDynamicType;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
-import org.apache.brooklyn.effector.core.EffectorBody;
 import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.feed.http.HttpFeed;
 import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNode.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNode.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNode.java
index bd8cf9b..2dd9067 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNode.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNode.java
@@ -33,8 +33,8 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.BrooklynVersion;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.config.MapConfigKey;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.entity.java.UsesJava;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.sensor.core.BasicAttributeSensor;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
index f1fd071..c1dd4ed 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
@@ -33,6 +33,8 @@ import org.apache.brooklyn.api.mgmt.TaskAdaptable;
 import org.apache.brooklyn.api.mgmt.ha.ManagementNodeState;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.render.RendererHints;
+import org.apache.brooklyn.core.effector.EffectorBody;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
@@ -42,8 +44,6 @@ import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.location.Locations;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.effector.core.EffectorBody;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.entity.brooklynnode.EntityHttpClient.ResponseCodePredicates;
 import org.apache.brooklyn.entity.brooklynnode.effector.BrooklynNodeUpgradeEffectorBody;
 import org.apache.brooklyn.entity.brooklynnode.effector.SetHighAvailabilityModeEffectorBody;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeSshDriver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeSshDriver.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeSshDriver.java
index 6962767..e862df8 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeSshDriver.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeSshDriver.java
@@ -29,9 +29,9 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.drivers.downloads.DownloadSubstituters;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNode.ExistingFileBehaviour;
 import org.apache.brooklyn.entity.java.JavaSoftwareProcessSshDriver;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/RemoteEffectorBuilder.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/RemoteEffectorBuilder.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/RemoteEffectorBuilder.java
index a031930..cf68641 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/RemoteEffectorBuilder.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/RemoteEffectorBuilder.java
@@ -23,8 +23,8 @@ import java.util.Collection;
 import java.util.Map;
 
 import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.effector.core.Effectors;
-import org.apache.brooklyn.effector.core.Effectors.EffectorBuilder;
+import org.apache.brooklyn.core.effector.Effectors;
+import org.apache.brooklyn.core.effector.Effectors.EffectorBuilder;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynEntityMirrorImpl.RemoteEffector;
 import org.apache.brooklyn.util.core.http.HttpToolResponse;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/BrooklynClusterUpgradeEffectorBody.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/BrooklynClusterUpgradeEffectorBody.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/BrooklynClusterUpgradeEffectorBody.java
index 3800855..319d5ba 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/BrooklynClusterUpgradeEffectorBody.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/BrooklynClusterUpgradeEffectorBody.java
@@ -31,12 +31,12 @@ import org.apache.brooklyn.api.entity.Group;
 import org.apache.brooklyn.api.mgmt.TaskAdaptable;
 import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
 import org.apache.brooklyn.api.mgmt.ha.ManagementNodeState;
+import org.apache.brooklyn.core.effector.EffectorBody;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.EntityPredicates;
 import org.apache.brooklyn.core.entity.EntityTasks;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
-import org.apache.brooklyn.effector.core.EffectorBody;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynCluster;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynCluster.SelectMasterEffector;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/BrooklynNodeUpgradeEffectorBody.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/BrooklynNodeUpgradeEffectorBody.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/BrooklynNodeUpgradeEffectorBody.java
index b1cb9be..c9f7dd7 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/BrooklynNodeUpgradeEffectorBody.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/BrooklynNodeUpgradeEffectorBody.java
@@ -29,12 +29,12 @@ import org.apache.brooklyn.api.mgmt.ha.ManagementNodeState;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.config.MapConfigKey;
+import org.apache.brooklyn.core.effector.EffectorBody;
+import org.apache.brooklyn.core.effector.Effectors;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.EntityTasks;
-import org.apache.brooklyn.effector.core.EffectorBody;
-import org.apache.brooklyn.effector.core.Effectors;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynCluster;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNodeDriver;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/SelectMasterEffectorBody.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/SelectMasterEffectorBody.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/SelectMasterEffectorBody.java
index 0ce0a91..bd05067 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/SelectMasterEffectorBody.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/SelectMasterEffectorBody.java
@@ -27,9 +27,9 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.Group;
 import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
 import org.apache.brooklyn.api.mgmt.ha.ManagementNodeState;
+import org.apache.brooklyn.core.effector.EffectorBody;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.EntityPredicates;
-import org.apache.brooklyn.effector.core.EffectorBody;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynCluster;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynCluster.SelectMasterEffector;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityModeEffectorBody.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityModeEffectorBody.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityModeEffectorBody.java
index 96d3e49..ca938e9 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityModeEffectorBody.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityModeEffectorBody.java
@@ -21,8 +21,8 @@ package org.apache.brooklyn.entity.brooklynnode.effector;
 import org.apache.brooklyn.api.effector.Effector;
 import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
 import org.apache.brooklyn.api.mgmt.ha.ManagementNodeState;
-import org.apache.brooklyn.effector.core.EffectorBody;
-import org.apache.brooklyn.effector.core.Effectors;
+import org.apache.brooklyn.core.effector.EffectorBody;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
 import org.apache.brooklyn.entity.brooklynnode.EntityHttpClient;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNode.SetHighAvailabilityModeEffector;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityPriorityEffectorBody.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityPriorityEffectorBody.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityPriorityEffectorBody.java
index 4fd1aa4..3560d49 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityPriorityEffectorBody.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityPriorityEffectorBody.java
@@ -19,8 +19,8 @@
 package org.apache.brooklyn.entity.brooklynnode.effector;
 
 import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.effector.core.EffectorBody;
-import org.apache.brooklyn.effector.core.Effectors;
+import org.apache.brooklyn.core.effector.EffectorBody;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
 import org.apache.brooklyn.entity.brooklynnode.EntityHttpClient;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNode.SetHighAvailabilityPriorityEffector;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefLifecycleEffectorTasks.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefLifecycleEffectorTasks.java b/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefLifecycleEffectorTasks.java
index 03b7518..869d34d 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefLifecycleEffectorTasks.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefLifecycleEffectorTasks.java
@@ -23,10 +23,10 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.MachineLocation;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.location.Machines;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefSoloTasks.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefSoloTasks.java b/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefSoloTasks.java
index 327b70b..505f37e 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefSoloTasks.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefSoloTasks.java
@@ -21,7 +21,7 @@ package org.apache.brooklyn.entity.chef;
 import java.util.Map;
 
 import org.apache.brooklyn.api.mgmt.TaskFactory;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.ssh.BashCommands;
 
 import com.google.common.annotations.Beta;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefTasks.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefTasks.java b/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefTasks.java
index c8a8b39..c1efa55 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefTasks.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefTasks.java
@@ -23,8 +23,8 @@ import java.util.Map;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.mgmt.TaskAdaptable;
 import org.apache.brooklyn.api.mgmt.TaskFactory;
-import org.apache.brooklyn.effector.core.EffectorTasks;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
+import org.apache.brooklyn.core.effector.EffectorTasks;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.file.ArchiveTasks;
 import org.apache.brooklyn.util.core.file.ArchiveUtils.ArchiveType;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/chef/KnifeConvergeTaskFactory.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/chef/KnifeConvergeTaskFactory.java b/software/base/src/main/java/org/apache/brooklyn/entity/chef/KnifeConvergeTaskFactory.java
index b66cd4e..c9d99b3 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/chef/KnifeConvergeTaskFactory.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/chef/KnifeConvergeTaskFactory.java
@@ -29,7 +29,7 @@ import com.google.common.base.Strings;
 import com.google.common.net.HostAndPort;
 
 import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.effector.core.EffectorTasks;
+import org.apache.brooklyn.core.effector.EffectorTasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/java/JavaSoftwareProcessSshDriver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/java/JavaSoftwareProcessSshDriver.java b/software/base/src/main/java/org/apache/brooklyn/entity/java/JavaSoftwareProcessSshDriver.java
index ce5f82d..c5720ca 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/java/JavaSoftwareProcessSshDriver.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/java/JavaSoftwareProcessSshDriver.java
@@ -28,11 +28,11 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.core.effector.EffectorTasks;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.effector.core.EffectorTasks;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.software.base.AbstractSoftwareProcessSshDriver;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java b/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java
index 193f804..2886257 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java
@@ -27,7 +27,7 @@ import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.effector.core.AddSensor;
+import org.apache.brooklyn.core.effector.AddSensor;
 import org.apache.brooklyn.sensor.core.DependentConfiguration;
 import org.apache.brooklyn.sensor.core.HttpRequestSensor;
 import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineEntity.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineEntity.java b/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineEntity.java
index 58c56ea..d3a1254 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineEntity.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineEntity.java
@@ -23,7 +23,7 @@ import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.annotation.EffectorParam;
-import org.apache.brooklyn.effector.core.MethodEffector;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess;
 import org.apache.brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineEntityImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineEntityImpl.java b/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineEntityImpl.java
index 1bb994d..72d7bef 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineEntityImpl.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineEntityImpl.java
@@ -23,8 +23,8 @@ import java.util.concurrent.TimeoutException;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.location.Machines;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.software.base.AbstractSoftwareProcessSshDriver;
 import org.apache.brooklyn.entity.software.base.EmptySoftwareProcessDriver;
 import org.apache.brooklyn.entity.software.base.EmptySoftwareProcessImpl;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/machine/pool/ServerPool.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/machine/pool/ServerPool.java b/software/base/src/main/java/org/apache/brooklyn/entity/machine/pool/ServerPool.java
index 42a4665..3cf29e7 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/machine/pool/ServerPool.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/machine/pool/ServerPool.java
@@ -34,9 +34,9 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.annotation.EffectorParam;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.core.location.cloud.CloudLocationConfig;
 import org.apache.brooklyn.core.location.dynamic.LocationOwner;
-import org.apache.brooklyn.effector.core.MethodEffector;
 import org.apache.brooklyn.entity.group.DynamicCluster;
 import org.apache.brooklyn.entity.machine.MachineEntity;
 import org.apache.brooklyn.sensor.core.Sensors;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/machine/pool/ServerPoolImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/machine/pool/ServerPoolImpl.java b/software/base/src/main/java/org/apache/brooklyn/entity/machine/pool/ServerPoolImpl.java
index 6089e3f..4307ff6 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/machine/pool/ServerPoolImpl.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/machine/pool/ServerPoolImpl.java
@@ -33,6 +33,7 @@ import org.apache.brooklyn.api.policy.PolicySpec;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
@@ -40,7 +41,6 @@ import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.location.BasicLocationDefinition;
 import org.apache.brooklyn.core.location.Machines;
 import org.apache.brooklyn.core.location.dynamic.DynamicLocation;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.entity.group.AbstractMembershipTrackingPolicy;
 import org.apache.brooklyn.entity.group.DynamicClusterImpl;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessSshDriver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessSshDriver.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessSshDriver.java
index a303f85..a64999c 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessSshDriver.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessSshDriver.java
@@ -30,12 +30,12 @@ import java.util.Set;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.entity.drivers.downloads.DownloadResolver;
 import org.apache.brooklyn.core.BrooklynLogging;
+import org.apache.brooklyn.core.effector.EffectorTasks;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.effector.core.EffectorTasks;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.software.base.lifecycle.NaiveScriptRunner;
 import org.apache.brooklyn.entity.software.base.lifecycle.ScriptHelper;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
index 0515166..24614af 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
@@ -40,6 +40,9 @@ import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.config.Sanitizer;
+import org.apache.brooklyn.core.effector.EffectorBody;
+import org.apache.brooklyn.core.effector.Effectors;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
 import org.apache.brooklyn.core.entity.Entities;
@@ -53,9 +56,6 @@ import org.apache.brooklyn.core.location.Locations;
 import org.apache.brooklyn.core.location.Machines;
 import org.apache.brooklyn.core.location.cloud.CloudLocationConfig;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.effector.core.EffectorBody;
-import org.apache.brooklyn.effector.core.Effectors;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.machine.MachineInitTasks;
 import org.apache.brooklyn.entity.machine.ProvidesProvisioningFlags;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/system_service/InitdServiceInstaller.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/system_service/InitdServiceInstaller.java b/software/base/src/main/java/org/apache/brooklyn/entity/system_service/InitdServiceInstaller.java
index ce64518..c0de92d 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/system_service/InitdServiceInstaller.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/system_service/InitdServiceInstaller.java
@@ -29,10 +29,10 @@ import org.apache.brooklyn.api.objs.HasShortName;
 import org.apache.brooklyn.api.sensor.Enricher;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.EffectorTasks;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.location.cloud.names.AbstractCloudMachineNamer;
-import org.apache.brooklyn.effector.core.EffectorTasks;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.util.collections.MutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/entity/system_service/SystemServiceEnricher.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/system_service/SystemServiceEnricher.java b/software/base/src/main/java/org/apache/brooklyn/entity/system_service/SystemServiceEnricher.java
index 35187f8..6470a4b 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/system_service/SystemServiceEnricher.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/system_service/SystemServiceEnricher.java
@@ -27,11 +27,11 @@ import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.api.sensor.Enricher;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.EffectorTasks;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags.WrappedStream;
-import org.apache.brooklyn.effector.core.EffectorTasks;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.sensor.enricher.AbstractEnricher;



[14/36] incubator-brooklyn git commit: Rename o.a.b.sensor.core to o.a.b.core.sensor

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/core/AttributeSensorAndConfigKey.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/AttributeSensorAndConfigKey.java b/core/src/main/java/org/apache/brooklyn/sensor/core/AttributeSensorAndConfigKey.java
deleted file mode 100644
index b777352..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/core/AttributeSensorAndConfigKey.java
+++ /dev/null
@@ -1,147 +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.core;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.mgmt.ManagementContext;
-import org.apache.brooklyn.api.sensor.Sensor;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.BasicConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.entity.AbstractEntity;
-import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
-import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
-import org.apache.brooklyn.util.core.flags.TypeCoercions;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.reflect.TypeToken;
-
-/**
-* A {@link Sensor} describing an attribute that can be configured with inputs that are used to derive the final value.
-* <p>
-* The {@link ConfigKey} will have the same name and description as the sensor but not necessarily the same type.
-* Conversion to set the sensor value from the config key must be supplied in a subclass.
-* <p>
-* {@link ConfigToAttributes#apply(EntityLocal, AttributeSensorAndConfigKey)} is useful to set the attribute from the sensor.
-*/
-public abstract class AttributeSensorAndConfigKey<ConfigType,SensorType> extends BasicAttributeSensor<SensorType> 
-        implements ConfigKey.HasConfigKey<ConfigType> {
-    private static final long serialVersionUID = -3103809215973264600L;
-    private static final Logger log = LoggerFactory.getLogger(AttributeSensorAndConfigKey.class);
-
-    private ConfigKey<ConfigType> configKey;
-
-    public AttributeSensorAndConfigKey(Class<ConfigType> configType, Class<SensorType> sensorType, String name) {
-        this(configType, sensorType, name, name, null);
-    }
-    
-    public AttributeSensorAndConfigKey(Class<ConfigType> configType, Class<SensorType> sensorType, String name, String description) {
-        this(TypeToken.of(configType), TypeToken.of(sensorType), name, description, null);
-    }
-    
-    public AttributeSensorAndConfigKey(Class<ConfigType> configType, Class<SensorType> sensorType, String name, String description, Object defaultValue) {
-        this(TypeToken.of(configType), TypeToken.of(sensorType), name, description, defaultValue);
-    }
-
-    public AttributeSensorAndConfigKey(TypeToken<ConfigType> configType, TypeToken<SensorType> sensorType, String name) {
-        this(configType, sensorType, name, null);
-    }
-
-    public AttributeSensorAndConfigKey(TypeToken<ConfigType> configType, TypeToken<SensorType> sensorType, String name, String description) {
-        this(configType, sensorType, name, description, null);
-    }
-
-    public AttributeSensorAndConfigKey(TypeToken<ConfigType> configType, TypeToken<SensorType> sensorType, String name, String description, Object defaultValue) {
-        super(sensorType, name, description);
-        ConfigType defaultValueTyped;
-        try {
-            defaultValueTyped = TypeCoercions.coerce(defaultValue, configType);
-        } catch (Exception e) {
-            log.warn("Invalid default value '"+defaultValue+"' for "+name+" (rethrowing: "+e, e);
-            throw Exceptions.propagate(e);
-        }
-        configKey = new BasicConfigKey<ConfigType>(configType, name, description, defaultValueTyped);
-    }
-
-    public AttributeSensorAndConfigKey(AttributeSensorAndConfigKey<ConfigType,SensorType> orig, ConfigType defaultValue) {
-        super(orig.getTypeToken(), orig.getName(), orig.getDescription());
-        configKey = ConfigKeys.newConfigKeyWithDefault(orig.configKey, 
-                TypeCoercions.coerce(defaultValue, orig.configKey.getTypeToken()));
-    }
-
-    public ConfigKey<ConfigType> getConfigKey() { return configKey; }
-    
-    /** returns the sensor value for this attribute on the given entity, if present,
-     * otherwise works out what the sensor value should be based on the config key's value
-     * <p>
-     * calls to this may allocate resources (e.g. ports) so should be called only once and 
-     * then (if non-null) assigned as the sensor's value
-     * <p>
-     * <b>(for this reason this method should generally not be invoked by callers except in tests and by the framework,
-     * and similarly should not be overridden; implement {@link #convertConfigToSensor(Object, Entity)} instead for single-execution calls.
-     * the framework calls this from {@link AbstractEntity#setAttribute(AttributeSensorAndConfigKey)} 
-     * typically via {@link ConfigToAttributes#apply(EntityLocal)} e.g. from SoftwareProcessImpl.preStart().)
-     * </b> 
-     */
-    public SensorType getAsSensorValue(Entity e) {
-        SensorType sensorValue = e.getAttribute(this);
-        if (sensorValue!=null) return sensorValue;
-        
-        ConfigType v = ((EntityLocal)e).getConfig(this);
-        try {
-            return convertConfigToSensor(v, e);
-        } catch (Throwable t) {
-            throw new IllegalArgumentException("Cannot convert config value "+v+" for sensor "+this+": "+t, t);
-        }
-    }
-
-    /**
-     * @see {@link #getAsSensorValue(Entity)}
-     * 
-     * Differs in that the config value is converted based on just the management context, rather
-     * than for a specific entity. For example, useful if using {@link BrooklynConfigKeys} in BrooklynWebServer.
-     * </b> 
-     */
-    public SensorType getAsSensorValue(ManagementContext managementContext) {
-        ConfigType v = managementContext.getConfig().getConfig(this);
-        try {
-            return convertConfigToSensor(v, managementContext);
-        } catch (Throwable t) {
-            throw new IllegalArgumentException("Cannot convert config value "+v+" for sensor "+this+": "+t, t);
-        }
-    }
-
-    /** converts the given ConfigType value to the corresponding SensorType value, 
-     * with respect to the given entity
-     * <p>
-     * this is invoked after checks whether the entity already has a value for the sensor,
-     * and the entity-specific config value is passed for convenience if set, 
-     * otherwise the config key default value is passed for convenience
-     * <p>
-     * this message should be allowed to return null if the conversion cannot be completed at this time */
-    protected abstract SensorType convertConfigToSensor(ConfigType value, Entity entity);
-
-    /**
-     * @see {@link #convertConfigToSensor(Object, Entity)}
-     */
-    protected abstract SensorType convertConfigToSensor(ConfigType value, ManagementContext entity);
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/core/BasicAttributeSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/BasicAttributeSensor.java b/core/src/main/java/org/apache/brooklyn/sensor/core/BasicAttributeSensor.java
deleted file mode 100644
index fa50cec..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/core/BasicAttributeSensor.java
+++ /dev/null
@@ -1,62 +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.core;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.api.sensor.Sensor;
-
-import com.google.common.reflect.TypeToken;
-
-/**
- * A {@link Sensor} describing an attribute change.
- */
-public class BasicAttributeSensor<T> extends BasicSensor<T> implements AttributeSensor<T> {
-    private static final long serialVersionUID = -2493209215974820300L;
-    
-    private final SensorPersistenceMode persistence;
-
-    public BasicAttributeSensor(Class<T> type, String name) {
-        this(type, name, name);
-    }
-    
-    public BasicAttributeSensor(Class<T> type, String name, String description) {
-        this(TypeToken.of(type), name, description);
-    }
-    
-    public BasicAttributeSensor(TypeToken<T> typeToken, String name) {
-        this(typeToken, name, name);
-    }
-    
-    public BasicAttributeSensor(TypeToken<T> typeToken, String name, String description) {
-        this(typeToken, name, description, SensorPersistenceMode.REQUIRED);
-    }
-    
-    public BasicAttributeSensor(TypeToken<T> typeToken, String name, String description, SensorPersistenceMode persistence) {
-        super(typeToken, name, description);
-        this.persistence = checkNotNull(persistence, "persistence");
-    }
-
-    @Override
-    public SensorPersistenceMode getPersistenceMode() {
-        // persistence could be null if deserializing state written by an old version; in which case default to 'required'
-        return (persistence != null) ? persistence : SensorPersistenceMode.REQUIRED;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/core/BasicAttributeSensorAndConfigKey.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/BasicAttributeSensorAndConfigKey.java b/core/src/main/java/org/apache/brooklyn/sensor/core/BasicAttributeSensorAndConfigKey.java
deleted file mode 100644
index 5f473a8..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/core/BasicAttributeSensorAndConfigKey.java
+++ /dev/null
@@ -1,114 +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.core;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.mgmt.ManagementContext;
-import org.apache.brooklyn.api.sensor.Sensor;
-import org.apache.brooklyn.config.ConfigKey;
-
-import com.google.common.reflect.TypeToken;
-
-/**
- * A {@link Sensor} describing an attribute that can be configured with a default value.
- *
- * The {@link ConfigKey} has the same type, name and description as the sensor,
- * and is typically used to populate the sensor's value at runtime.
- */
-public class BasicAttributeSensorAndConfigKey<T> extends AttributeSensorAndConfigKey<T,T> {
-    
-    private static final long serialVersionUID = -2204916730008559688L;
-
-    public BasicAttributeSensorAndConfigKey(Class<T> type, String name) {
-        this(type, name, name, null);
-    }
-    public BasicAttributeSensorAndConfigKey(Class<T> type, String name, String description) {
-        this(type, name, description, null);
-    }
-    public BasicAttributeSensorAndConfigKey(Class<T> type, String name, String description, T defaultValue) {
-        super(type, type, name, description, defaultValue);
-    }
-
-    public BasicAttributeSensorAndConfigKey(TypeToken<T> type, String name) {
-        super(type, type, name);
-    }
-
-    public BasicAttributeSensorAndConfigKey(TypeToken<T> type, String name, String description) {
-        super(type, type, name, description);
-    }
-
-    public BasicAttributeSensorAndConfigKey(TypeToken<T> type, String name, String description, Object defaultValue) {
-        super(type, type, name, description, defaultValue);
-    }
-
-    public BasicAttributeSensorAndConfigKey(AttributeSensorAndConfigKey<T,T> orig, T defaultValue) {
-        super(orig, defaultValue);
-    }
-    
-    @Override
-    protected T convertConfigToSensor(T value, Entity entity) { return value; }
-
-    @Override
-    protected T convertConfigToSensor(T value, ManagementContext managementContext) { return value; }
-    
-    public static class StringAttributeSensorAndConfigKey extends BasicAttributeSensorAndConfigKey<String> {
-
-        private static final long serialVersionUID = 810512615528081865L;
-
-        public StringAttributeSensorAndConfigKey(AttributeSensorAndConfigKey<String,String> orig, String defaultValue) {
-            super(orig, defaultValue);
-        }
-
-        public StringAttributeSensorAndConfigKey(String name, String description, String defaultValue) {
-            super(String.class, name, description, defaultValue);
-        }
-
-        public StringAttributeSensorAndConfigKey(String name, String description) {
-            super(String.class, name, description);
-        }
-
-        public StringAttributeSensorAndConfigKey(String name) {
-            super(String.class, name);
-        }
-        
-    }
-    
-    public static class IntegerAttributeSensorAndConfigKey extends BasicAttributeSensorAndConfigKey<Integer> {
-
-        private static final long serialVersionUID = 7159564523829723929L;
-
-        public IntegerAttributeSensorAndConfigKey(AttributeSensorAndConfigKey<Integer,Integer> orig, Integer defaultValue) {
-            super(orig, defaultValue);
-        }
-
-        public IntegerAttributeSensorAndConfigKey(String name, String description, Integer defaultValue) {
-            super(Integer.class, name, description, defaultValue);
-        }
-
-        public IntegerAttributeSensorAndConfigKey(String name, String description) {
-            super(Integer.class, name, description);
-        }
-
-        public IntegerAttributeSensorAndConfigKey(String name) {
-            super(Integer.class, name);
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/core/BasicNotificationSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/BasicNotificationSensor.java b/core/src/main/java/org/apache/brooklyn/sensor/core/BasicNotificationSensor.java
deleted file mode 100644
index 627e3c8..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/core/BasicNotificationSensor.java
+++ /dev/null
@@ -1,36 +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.core;
-
-import org.apache.brooklyn.api.sensor.Sensor;
-
-/**
- * A {@link Sensor} used to notify subscribers about events.
- */
-public class BasicNotificationSensor<T> extends BasicSensor<T> {
-    private static final long serialVersionUID = -7670909215973264600L;
-
-    public BasicNotificationSensor(Class<T> type, String name) {
-        this(type, name, name);
-    }
-    
-    public BasicNotificationSensor(Class<T> type, String name, String description) {
-        super(type, name, description);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/core/BasicSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/BasicSensor.java b/core/src/main/java/org/apache/brooklyn/sensor/core/BasicSensor.java
deleted file mode 100644
index 439fbb2..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/core/BasicSensor.java
+++ /dev/null
@@ -1,114 +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.core;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.List;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.sensor.Sensor;
-import org.apache.brooklyn.api.sensor.SensorEvent;
-import org.apache.brooklyn.util.guava.TypeTokens;
-
-import com.google.common.base.Objects;
-import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableList;
-import com.google.common.reflect.TypeToken;
-
-/**
- * Parent for all {@link Sensor}s.
- */
-public class BasicSensor<T> implements Sensor<T> {
-    private static final long serialVersionUID = -3762018534086101323L;
-    
-    private static final Splitter dots = Splitter.on('.');
-
-    private TypeToken<T> typeToken;
-    private Class<? super T> type;
-    private String name;
-    private String description;
-    private transient List<String> nameParts;
-    
-    // FIXME In groovy, fields were `public final` with a default constructor; do we need the gson?
-    public BasicSensor() { /* for gson */ }
-
-    /** name is typically a dot-separated identifier; description is optional */
-    public BasicSensor(Class<T> type, String name) {
-        this(type, name, name);
-    }
-    
-    public BasicSensor(Class<T> type, String name, String description) {
-        this(TypeToken.of(type), name, description);
-    }
-    
-    public BasicSensor(TypeToken<T> typeToken, String name, String description) {
-        this.typeToken = TypeTokens.getTypeTokenIfNotRaw(checkNotNull(typeToken, "typeToken"));
-        this.type = TypeTokens.getRawTypeIfRaw(typeToken);
-        this.name = checkNotNull(name, "name");
-        this.description = description;
-    }
-
-    /** @see Sensor#getTypeToken() */
-    public TypeToken<T> getTypeToken() { return TypeTokens.getTypeToken(typeToken, type); }
-    
-    /** @see Sensor#getType() */
-    public Class<? super T> getType() { return TypeTokens.getRawType(typeToken, type); }
- 
-    /** @see Sensor#getTypeName() */
-    public String getTypeName() { 
-        return getType().getName();
-    }
- 
-    /** @see Sensor#getName() */
-    public String getName() { return name; }
- 
-    /** @see Sensor#getNameParts() */
-    public synchronized List<String> getNameParts() {
-        if (nameParts==null) nameParts = ImmutableList.copyOf(dots.split(name));
-        return nameParts; 
-    }
- 
-    /** @see Sensor#getDescription() */
-    public String getDescription() { return description; }
-    
-    /** @see Sensor#newEvent(Entity, Object) */
-    public SensorEvent<T> newEvent(Entity producer, T value) {
-        return new BasicSensorEvent<T>(this, producer, value);
-    }
-    
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(getTypeName(), name, description);
-    }
- 
-    @Override
-    public boolean equals(Object other) {
-        if (this==other) return true;
-        if (!(other instanceof BasicSensor)) return false;
-        BasicSensor<?> o = (BasicSensor<?>) other;
-        
-        return Objects.equal(getTypeName(), o.getTypeName()) && Objects.equal(name, o.name) && Objects.equal(description, o.description);
-    }
-    
-    @Override
-    public String toString() {
-        return String.format("Sensor: %s (%s)", name, getTypeName());
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/core/BasicSensorEvent.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/BasicSensorEvent.java b/core/src/main/java/org/apache/brooklyn/sensor/core/BasicSensorEvent.java
deleted file mode 100644
index fb0f7a9..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/core/BasicSensorEvent.java
+++ /dev/null
@@ -1,112 +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.core;
-
-import java.util.ConcurrentModificationException;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.sensor.Sensor;
-import org.apache.brooklyn.api.sensor.SensorEvent;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Objects;
-
-/**
- * A {@link SensorEvent} containing data from a {@link Sensor} generated by an {@link Entity}.
- */
-public class BasicSensorEvent<T> implements SensorEvent<T> {
-    
-    private static final Logger log = LoggerFactory.getLogger(BasicSensorEvent.class);
-    
-    private final Sensor<T> sensor;
-    private final Entity source;
-    private final T value;
-    private final long timestamp;
-    
-    public T getValue() { return value; }
-
-    public Sensor<T> getSensor() { return sensor; }
-
-    public Entity getSource() { return source; }
-
-    public long getTimestamp() { return timestamp; }
-
-    /** arguments should not be null (except in certain limited testing situations) */
-    public BasicSensorEvent(Sensor<T> sensor, Entity source, T value) {
-        this(sensor, source, value, System.currentTimeMillis());
-    }
-    
-    public BasicSensorEvent(Sensor<T> sensor, Entity source, T value, long timestamp) {
-        this.sensor = sensor;
-        this.source = source;
-        this.value = value;
-        this.timestamp = timestamp;
-    }
-    
-    public static <T> SensorEvent<T> of(Sensor<T> sensor, Entity source, T value, long timestamp) {
-        return new BasicSensorEvent<T>(sensor, source, value, timestamp);
-    }
-
-    @SuppressWarnings("unchecked")
-    public static <T> SensorEvent<T> ofUnchecked(Sensor<T> sensor, Entity source, Object value, long timestamp) {
-        return new BasicSensorEvent<T>(sensor, source, (T)value, timestamp);
-    }
-
-    public static <T> SensorEvent<T> of(Sensor<T> sensor, Entity source, T value) {
-        return new BasicSensorEvent<T>(sensor, source, value);
-    }
-
-    @SuppressWarnings("unchecked")
-    public static <T> SensorEvent<T> ofUnchecked(Sensor<T> sensor, Entity source, Object value) {
-        return new BasicSensorEvent<T>(sensor, source, (T)value);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(sensor, source, value);
-    }   
-
-    /**
-     * Any SensorEvents are equal if their sensor, source and value are equal.
-     * Ignore timestamp for ease of use in unit tests.   
-     */
-    @Override
-    public boolean equals(Object o) {
-        if (!(o instanceof SensorEvent)) return false;
-        SensorEvent<?> other = (SensorEvent<?>) o;
-        return Objects.equal(sensor, other.getSensor()) && Objects.equal(source, other.getSource()) &&
-                Objects.equal(value, other.getValue());
-    }
-    
-    @Override
-    public String toString() {
-        try {
-            return source+"."+sensor+"="+value+" @ "+timestamp;
-        } catch (ConcurrentModificationException e) {
-            // TODO occasional CME observed on shutdown, wrt map, e.g. in UrlMappingTest
-            // transformations should set a copy of the map; see e.g. in ServiceStateLogic.updateMapSensor
-            String result = getClass()+":"+source+"."+sensor+"@"+timestamp;
-            log.warn("Error creating string for " + result + " (ignoring): " + e);
-            if (log.isDebugEnabled())
-                log.debug("Trace for error creating string for " + result + " (ignoring): " + e, e);
-            return result;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/core/DependentConfiguration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/DependentConfiguration.java b/core/src/main/java/org/apache/brooklyn/sensor/core/DependentConfiguration.java
deleted file mode 100644
index 9327b19..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/core/DependentConfiguration.java
+++ /dev/null
@@ -1,823 +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.core;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import groovy.lang.Closure;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.mgmt.ExecutionContext;
-import org.apache.brooklyn.api.mgmt.SubscriptionHandle;
-import org.apache.brooklyn.api.mgmt.Task;
-import org.apache.brooklyn.api.mgmt.TaskAdaptable;
-import org.apache.brooklyn.api.mgmt.TaskFactory;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-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.entity.Attributes;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
-import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.util.collections.CollectionFunctionals;
-import org.apache.brooklyn.util.collections.MutableList;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.task.BasicExecutionContext;
-import org.apache.brooklyn.util.core.task.BasicTask;
-import org.apache.brooklyn.util.core.task.DeferredSupplier;
-import org.apache.brooklyn.util.core.task.DynamicTasks;
-import org.apache.brooklyn.util.core.task.ParallelTask;
-import org.apache.brooklyn.util.core.task.TaskInternal;
-import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.core.task.ValueResolver;
-import org.apache.brooklyn.util.exceptions.CompoundRuntimeException;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.exceptions.NotManagedException;
-import org.apache.brooklyn.util.exceptions.RuntimeTimeoutException;
-import org.apache.brooklyn.util.groovy.GroovyJavaMethods;
-import org.apache.brooklyn.util.guava.Functionals;
-import org.apache.brooklyn.util.guava.Maybe;
-import org.apache.brooklyn.util.text.Strings;
-import org.apache.brooklyn.util.time.CountdownTimer;
-import org.apache.brooklyn.util.time.Duration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Function;
-import com.google.common.base.Functions;
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-import com.google.common.base.Throwables;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-
-/** Conveniences for making tasks which run in entity {@link ExecutionContext}s, subscribing to attributes from other entities, possibly transforming those;
- * these {@link Task} instances are typically passed in {@link EntityLocal#setConfig(ConfigKey, Object)}.
- * <p>
- * If using a lot it may be useful to:
- * <pre>
- * {@code
- *   import static brooklyn.event.basic.DependentConfiguration.*;
- * }
- * </pre>
- */
-public class DependentConfiguration {
-
-    private static final Logger LOG = LoggerFactory.getLogger(DependentConfiguration.class);
-    
-    //not instantiable, only a static helper
-    private DependentConfiguration() {}
-
-    /**
-     * Default readiness is Groovy truth.
-     * 
-     * @see #attributeWhenReady(Entity, AttributeSensor, Predicate)
-     */
-    public static <T> Task<T> attributeWhenReady(Entity source, AttributeSensor<T> sensor) {
-        return attributeWhenReady(source, sensor, GroovyJavaMethods.truthPredicate());
-    }
-    
-    public static <T> Task<T> attributeWhenReady(Entity source, AttributeSensor<T> sensor, Closure<Boolean> ready) {
-        Predicate<Object> readyPredicate = (ready != null) ? GroovyJavaMethods.<Object>predicateFromClosure(ready) : GroovyJavaMethods.truthPredicate();
-        return attributeWhenReady(source, sensor, readyPredicate);
-    }
-    
-    /** returns an unsubmitted {@link Task} which blocks until the given sensor on the given source entity gives a value that satisfies ready, then returns that value;
-     * particular useful in Entity configuration where config will block until Tasks have a value
-     */
-    public static <T> Task<T> attributeWhenReady(final Entity source, final AttributeSensor<T> sensor, final Predicate<? super T> ready) {
-        Builder<T, T> builder = builder().attributeWhenReady(source, sensor);
-        if (ready != null) builder.readiness(ready);
-        return builder.build();
-
-    }
-
-    public static <T,V> Task<V> attributePostProcessedWhenReady(Entity source, AttributeSensor<T> sensor, Closure<Boolean> ready, Closure<V> postProcess) {
-        Predicate<? super T> readyPredicate = (ready != null) ? GroovyJavaMethods.predicateFromClosure(ready) : GroovyJavaMethods.truthPredicate();
-        Function<? super T, V> postProcessFunction = GroovyJavaMethods.<T,V>functionFromClosure(postProcess);
-        return attributePostProcessedWhenReady(source, sensor, readyPredicate, postProcessFunction);
-    }
-
-    public static <T,V> Task<V> attributePostProcessedWhenReady(Entity source, AttributeSensor<T> sensor, Closure<V> postProcess) {
-        return attributePostProcessedWhenReady(source, sensor, GroovyJavaMethods.truthPredicate(), GroovyJavaMethods.<T,V>functionFromClosure(postProcess));
-    }
-
-    public static <T> Task<T> valueWhenAttributeReady(Entity source, AttributeSensor<T> sensor, T value) {
-        return DependentConfiguration.<T,T>attributePostProcessedWhenReady(source, sensor, GroovyJavaMethods.truthPredicate(), Functions.constant(value));
-    }
-
-    public static <T,V> Task<V> valueWhenAttributeReady(Entity source, AttributeSensor<T> sensor, Function<? super T,V> valueProvider) {
-        return attributePostProcessedWhenReady(source, sensor, GroovyJavaMethods.truthPredicate(), valueProvider);
-    }
-    
-    public static <T,V> Task<V> valueWhenAttributeReady(Entity source, AttributeSensor<T> sensor, Closure<V> valueProvider) {
-        return attributePostProcessedWhenReady(source, sensor, GroovyJavaMethods.truthPredicate(), valueProvider);
-    }
-    
-    public static <T,V> Task<V> attributePostProcessedWhenReady(final Entity source, final AttributeSensor<T> sensor, final Predicate<? super T> ready, final Closure<V> postProcess) {
-        return attributePostProcessedWhenReady(source, sensor, ready, GroovyJavaMethods.<T,V>functionFromClosure(postProcess));
-    }
-    
-    @SuppressWarnings("unchecked")
-    public static <T,V> Task<V> attributePostProcessedWhenReady(final Entity source, final AttributeSensor<T> sensor, final Predicate<? super T> ready, final Function<? super T,V> postProcess) {
-        Builder<T,T> builder1 = DependentConfiguration.builder().attributeWhenReady(source, sensor);
-        // messy generics here to support null postProcess; would be nice to disallow that here
-        Builder<T,V> builder;
-        if (postProcess != null) {
-            builder = builder1.postProcess(postProcess);
-        } else {
-            builder = (Builder<T,V>)builder1;
-        }
-        if (ready != null) builder.readiness(ready);
-        
-        return builder.build();
-    }
-
-    public static <T> T waitInTaskForAttributeReady(Entity source, AttributeSensor<T> sensor, Predicate<? super T> ready) {
-        return waitInTaskForAttributeReady(source, sensor, ready, ImmutableList.<AttributeAndSensorCondition<?>>of());
-    }
-
-    public static <T> T waitInTaskForAttributeReady(final Entity source, final AttributeSensor<T> sensor, Predicate<? super T> ready, List<AttributeAndSensorCondition<?>> abortConditions) {
-        String blockingDetails = "Waiting for ready from "+source+" "+sensor+" (subscription)";
-        return waitInTaskForAttributeReady(source, sensor, ready, abortConditions, blockingDetails);
-    }
-    
-    // TODO would be nice to have an easy semantics for whenServiceUp (cf DynamicWebAppClusterImpl.whenServiceUp)
-    
-    public static <T> T waitInTaskForAttributeReady(final Entity source, final AttributeSensor<T> sensor, Predicate<? super T> ready, List<AttributeAndSensorCondition<?>> abortConditions, String blockingDetails) {
-        return new WaitInTaskForAttributeReady<T,T>(source, sensor, ready, abortConditions, blockingDetails).call();
-    }
-    
-    protected static class WaitInTaskForAttributeReady<T,V> implements Callable<V> {
-
-        /* This is a change since before Oct 2014. Previously it would continue to poll,
-         * (maybe finding a different error) if the target entity becomes unmanaged. 
-         * Now it actively checks unmanaged by default, and still throws although it might 
-         * now find a different problem. */
-        private final static boolean DEFAULT_IGNORE_UNMANAGED = false;
-        
-        protected final Entity source;
-        protected final AttributeSensor<T> sensor;
-        protected final Predicate<? super T> ready;
-        protected final List<AttributeAndSensorCondition<?>> abortSensorConditions;
-        protected final String blockingDetails;
-        protected final Function<? super T,? extends V> postProcess;
-        protected final Duration timeout;
-        protected final Maybe<V> onTimeout;
-        protected final boolean ignoreUnmanaged;
-        protected final Maybe<V> onUnmanaged;
-        // TODO onError Continue / Throw / Return(V)
-        
-        protected WaitInTaskForAttributeReady(Builder<T, V> builder) {
-            this.source = builder.source;
-            this.sensor = builder.sensor;
-            this.ready = builder.readiness;
-            this.abortSensorConditions = builder.abortSensorConditions;
-            this.blockingDetails = builder.blockingDetails;
-            this.postProcess = builder.postProcess;
-            this.timeout = builder.timeout;
-            this.onTimeout = builder.onTimeout;
-            this.ignoreUnmanaged = builder.ignoreUnmanaged;
-            this.onUnmanaged = builder.onUnmanaged;
-        }
-        
-        private WaitInTaskForAttributeReady(Entity source, AttributeSensor<T> sensor, Predicate<? super T> ready,
-                List<AttributeAndSensorCondition<?>> abortConditions, String blockingDetails) {
-            this.source = source;
-            this.sensor = sensor;
-            this.ready = ready;
-            this.abortSensorConditions = abortConditions;
-            this.blockingDetails = blockingDetails;
-            
-            this.timeout = Duration.PRACTICALLY_FOREVER;
-            this.onTimeout = Maybe.absent();
-            this.ignoreUnmanaged = DEFAULT_IGNORE_UNMANAGED;
-            this.onUnmanaged = Maybe.absent();
-            this.postProcess = null;
-        }
-
-        @SuppressWarnings("unchecked")
-        protected V postProcess(T value) {
-            if (this.postProcess!=null) return postProcess.apply(value);
-            // if no post-processing assume the types are correct
-            return (V) value;
-        }
-        
-        protected boolean ready(T value) {
-            if (ready!=null) return ready.apply(value);
-            return GroovyJavaMethods.truth(value);
-        }
-        
-        @SuppressWarnings({ "rawtypes", "unchecked" })
-        @Override
-        public V call() {
-            T value = source.getAttribute(sensor);
-
-            // return immediately if either the ready predicate or the abort conditions hold
-            if (ready(value)) return postProcess(value);
-
-            final List<Exception> abortionExceptions = Lists.newCopyOnWriteArrayList();
-            long start = System.currentTimeMillis();
-            
-            for (AttributeAndSensorCondition abortCondition : abortSensorConditions) {
-                Object abortValue = abortCondition.source.getAttribute(abortCondition.sensor);
-                if (abortCondition.predicate.apply(abortValue)) {
-                    abortionExceptions.add(new Exception("Abort due to "+abortCondition.source+" -> "+abortCondition.sensor));
-                }
-            }
-            if (abortionExceptions.size() > 0) {
-                throw new CompoundRuntimeException("Aborted waiting for ready from "+source+" "+sensor, abortionExceptions);
-            }
-
-            TaskInternal<?> current = (TaskInternal<?>) Tasks.current();
-            if (current == null) throw new IllegalStateException("Should only be invoked in a running task");
-            Entity entity = BrooklynTaskTags.getTargetOrContextEntity(current);
-            if (entity == null) throw new IllegalStateException("Should only be invoked in a running task with an entity tag; "+
-                current+" has no entity tag ("+current.getStatusDetail(false)+")");
-            
-            final LinkedList<T> publishedValues = new LinkedList<T>();
-            final Semaphore semaphore = new Semaphore(0); // could use Exchanger
-            SubscriptionHandle subscription = null;
-            List<SubscriptionHandle> abortSubscriptions = Lists.newArrayList();
-            
-            try {
-                subscription = ((EntityInternal)entity).getSubscriptionContext().subscribe(source, sensor, new SensorEventListener<T>() {
-                    @Override public void onEvent(SensorEvent<T> event) {
-                        synchronized (publishedValues) { publishedValues.add(event.getValue()); }
-                        semaphore.release();
-                    }});
-                for (final AttributeAndSensorCondition abortCondition : abortSensorConditions) {
-                    abortSubscriptions.add(((EntityInternal)entity).getSubscriptionContext().subscribe(abortCondition.source, abortCondition.sensor, new SensorEventListener<Object>() {
-                        @Override public void onEvent(SensorEvent<Object> event) {
-                            if (abortCondition.predicate.apply(event.getValue())) {
-                                abortionExceptions.add(new Exception("Abort due to "+abortCondition.source+" -> "+abortCondition.sensor));
-                                semaphore.release();
-                            }
-                        }}));
-                    Object abortValue = abortCondition.source.getAttribute(abortCondition.sensor);
-                    if (abortCondition.predicate.apply(abortValue)) {
-                        abortionExceptions.add(new Exception("Abort due to "+abortCondition.source+" -> "+abortCondition.sensor));
-                    }
-                }
-                if (abortionExceptions.size() > 0) {
-                    throw new CompoundRuntimeException("Aborted waiting for ready from "+source+" "+sensor, abortionExceptions);
-                }
-
-                CountdownTimer timer = timeout!=null ? timeout.countdownTimer() : null;
-                Duration maxPeriod = ValueResolver.PRETTY_QUICK_WAIT;
-                Duration nextPeriod = ValueResolver.REAL_QUICK_PERIOD;
-                while (true) {
-                    // check the source on initial run (could be done outside the loop) 
-                    // and also (optionally) on each iteration in case it is more recent 
-                    value = source.getAttribute(sensor);
-                    if (ready(value)) break;
-
-                    if (timer!=null) {
-                        if (timer.getDurationRemaining().isShorterThan(nextPeriod)) {
-                            nextPeriod = timer.getDurationRemaining();
-                        }
-                        if (timer.isExpired()) {
-                            if (onTimeout.isPresent()) return onTimeout.get();
-                            throw new RuntimeTimeoutException("Unsatisfied after "+Duration.sinceUtc(start));
-                        }
-                    }
-
-                    String prevBlockingDetails = current.setBlockingDetails(blockingDetails);
-                    try {
-                        if (semaphore.tryAcquire(nextPeriod.toMilliseconds(), TimeUnit.MILLISECONDS)) {
-                            // immediately release so we are available for the next check
-                            semaphore.release();
-                            // if other permits have been made available (e.g. multiple notifications) drain them all as no point running multiple times
-                            semaphore.drainPermits();
-                        }
-                    } finally {
-                        current.setBlockingDetails(prevBlockingDetails);
-                    }
-
-                    // check any subscribed values which have come in first
-                    while (true) {
-                        synchronized (publishedValues) {
-                            if (publishedValues.isEmpty()) break;
-                            value = publishedValues.pop(); 
-                        }
-                        if (ready(value)) break;
-                    }
-
-                    // if unmanaged then ignore the other abort conditions
-                    if (!ignoreUnmanaged && Entities.isNoLongerManaged(entity)) {
-                        if (onUnmanaged.isPresent()) return onUnmanaged.get();
-                        throw new NotManagedException(entity);                        
-                    }
-                    
-                    if (abortionExceptions.size() > 0) {
-                        throw new CompoundRuntimeException("Aborted waiting for ready from "+source+" "+sensor, abortionExceptions);
-                    }
-
-                    nextPeriod = nextPeriod.times(2).upperBound(maxPeriod);
-                }
-                if (LOG.isDebugEnabled()) LOG.debug("Attribute-ready for {} in entity {}", sensor, source);
-                return postProcess(value);
-            } catch (InterruptedException e) {
-                throw Exceptions.propagate(e);
-            } finally {
-                if (subscription != null) {
-                    ((EntityInternal)entity).getSubscriptionContext().unsubscribe(subscription);
-                }
-                for (SubscriptionHandle handle : abortSubscriptions) {
-                    ((EntityInternal)entity).getSubscriptionContext().unsubscribe(handle);
-                }
-            }
-        }
-    }
-    
-    /**
-     * Returns a {@link Task} which blocks until the given job returns, then returns the value of that job.
-     * 
-     * @deprecated since 0.7; code will be moved into test utilities
-     */
-    @Deprecated
-    public static <T> Task<T> whenDone(Callable<T> job) {
-        return new BasicTask<T>(MutableMap.of("tag", "whenDone", "displayName", "waiting for job"), job);
-    }
-
-    /**
-     * Returns a {@link Task} which waits for the result of first parameter, then applies the function in the second
-     * parameter to it, returning that result.
-     *
-     * Particular useful in Entity configuration where config will block until Tasks have completed,
-     * allowing for example an {@link #attributeWhenReady(Entity, AttributeSensor, Predicate)} expression to be
-     * passed in the first argument then transformed by the function in the second argument to generate
-     * the value that is used for the configuration
-     */
-    public static <U,T> Task<T> transform(final Task<U> task, final Function<U,T> transformer) {
-        return transform(MutableMap.of("displayName", "transforming "+task), task, transformer);
-    }
- 
-    /** @see #transform(Task, Function) */
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    public static <U,T> Task<T> transform(Task<U> task, Closure transformer) {
-        return transform(task, GroovyJavaMethods.functionFromClosure(transformer));
-    }
-    
-    /** @see #transform(Task, Function) */
-    @SuppressWarnings({ "rawtypes" })
-    public static <U,T> Task<T> transform(final Map flags, final TaskAdaptable<U> task, final Function<U,T> transformer) {
-        return new BasicTask<T>(flags, new Callable<T>() {
-            public T call() throws Exception {
-                if (!task.asTask().isSubmitted()) {
-                    BasicExecutionContext.getCurrentExecutionContext().submit(task);
-                } 
-                return transformer.apply(task.asTask().get());
-            }});        
-    }
-     
-    /** Returns a task which waits for multiple other tasks (submitting if necessary)
-     * and performs arbitrary computation over the List of results.
-     * @see #transform(Task, Function) but note argument order is reversed (counterintuitive) to allow for varargs */
-    public static <U,T> Task<T> transformMultiple(Function<List<U>,T> transformer, @SuppressWarnings("unchecked") TaskAdaptable<U> ...tasks) {
-        return transformMultiple(MutableMap.of("displayName", "transforming multiple"), transformer, tasks);
-    }
-
-    /** @see #transformMultiple(Function, TaskAdaptable...) */
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    public static <U,T> Task<T> transformMultiple(Closure transformer, TaskAdaptable<U> ...tasks) {
-        return transformMultiple(GroovyJavaMethods.functionFromClosure(transformer), tasks);
-    }
-
-    /** @see #transformMultiple(Function, TaskAdaptable...) */
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    public static <U,T> Task<T> transformMultiple(Map flags, Closure transformer, TaskAdaptable<U> ...tasks) {
-        return transformMultiple(flags, GroovyJavaMethods.functionFromClosure(transformer), tasks);
-    }
-    
-    /** @see #transformMultiple(Function, TaskAdaptable...) */
-    @SuppressWarnings({ "rawtypes" })
-    public static <U,T> Task<T> transformMultiple(Map flags, final Function<List<U>,T> transformer, @SuppressWarnings("unchecked") TaskAdaptable<U> ...tasks) {
-        return transformMultiple(flags, transformer, Arrays.asList(tasks));
-    }
-    @SuppressWarnings({ "rawtypes" })
-    public static <U,T> Task<T> transformMultiple(Map flags, final Function<List<U>,T> transformer, Collection<? extends TaskAdaptable<U>> tasks) {
-        if (tasks.size()==1) {
-            return transform(flags, Iterables.getOnlyElement(tasks), new Function<U,T>() {
-                @Override
-                @Nullable
-                public T apply(@Nullable U input) {
-                    return transformer.apply(ImmutableList.of(input));
-                }
-            });
-        }
-        return transform(flags, new ParallelTask<U>(tasks), transformer);
-    }
-
-
-    /** Method which returns a Future containing a string formatted using String.format,
-     * where the arguments can be normal objects or tasks;
-     * tasks will be waited on (submitted if necessary) and their results substituted in the call
-     * to String.format.
-     * <p>
-     * Example:
-     * <pre>
-     * {@code
-     *   setConfig(URL, DependentConfiguration.formatString("%s:%s", 
-     *           DependentConfiguration.attributeWhenReady(target, Target.HOSTNAME),
-     *           DependentConfiguration.attributeWhenReady(target, Target.PORT) ) );
-     * }
-     * </pre>
-     */
-    @SuppressWarnings("unchecked")
-    public static Task<String> formatString(final String spec, final Object ...args) {
-        List<TaskAdaptable<Object>> taskArgs = Lists.newArrayList();
-        for (Object arg: args) {
-            if (arg instanceof TaskAdaptable) taskArgs.add((TaskAdaptable<Object>)arg);
-            else if (arg instanceof TaskFactory) taskArgs.add( ((TaskFactory<TaskAdaptable<Object>>)arg).newTask() );
-        }
-            
-        return transformMultiple(
-            MutableMap.<String,String>of("displayName", "formatting '"+spec+"' with "+taskArgs.size()+" task"+(taskArgs.size()!=1?"s":"")), 
-                new Function<List<Object>, String>() {
-            @Override public String apply(List<Object> input) {
-                Iterator<?> tri = input.iterator();
-                Object[] vv = new Object[args.length];
-                int i=0;
-                for (Object arg : args) {
-                    if (arg instanceof TaskAdaptable || arg instanceof TaskFactory) vv[i] = tri.next();
-                    else if (arg instanceof DeferredSupplier) vv[i] = ((DeferredSupplier<?>) arg).get();
-                    else vv[i] = arg;
-                    i++;
-                }
-                return String.format(spec, vv);
-            }},
-            taskArgs);
-    }
-
-    /** returns a task for parallel execution returning a list of values for the given sensor for the given entity list, 
-     * optionally when the values satisfy a given readiness predicate (defaulting to groovy truth if not supplied) */
-    public static <T> Task<List<T>> listAttributesWhenReady(AttributeSensor<T> sensor, Iterable<Entity> entities) {
-        return listAttributesWhenReady(sensor, entities, GroovyJavaMethods.truthPredicate());
-    }
-    
-    public static <T> Task<List<T>> listAttributesWhenReady(AttributeSensor<T> sensor, Iterable<Entity> entities, Closure<Boolean> readiness) {
-        Predicate<Object> readinessPredicate = (readiness != null) ? GroovyJavaMethods.<Object>predicateFromClosure(readiness) : GroovyJavaMethods.truthPredicate();
-        return listAttributesWhenReady(sensor, entities, readinessPredicate);
-    }
-    
-    /** returns a task for parallel execution returning a list of values of the given sensor list on the given entity, 
-     * optionally when the values satisfy a given readiness predicate (defaulting to groovy truth if not supplied) */    
-    public static <T> Task<List<T>> listAttributesWhenReady(final AttributeSensor<T> sensor, Iterable<Entity> entities, Predicate<? super T> readiness) {
-        if (readiness == null) readiness = GroovyJavaMethods.truthPredicate();
-        return builder().attributeWhenReadyFromMultiple(entities, sensor, readiness).build();
-    }
-
-    /** @see #waitForTask(Task, Entity, String) */
-    public static <T> T waitForTask(Task<T> t, Entity context) throws InterruptedException {
-        return waitForTask(t, context, null);
-    }
-    
-    /** blocks until the given task completes, submitting if necessary, returning the result of that task;
-     * optional contextMessage is available in status if this is running in a task
-     */
-    @SuppressWarnings("unchecked")
-    public static <T> T waitForTask(Task<T> t, Entity context, String contextMessage) throws InterruptedException {
-        try {
-            return (T) Tasks.resolveValue(t, Object.class, ((EntityInternal)context).getExecutionContext(), contextMessage);
-        } catch (ExecutionException e) {
-            throw Throwables.propagate(e);
-        }
-    }
-    
-    public static class AttributeAndSensorCondition<T> {
-        protected final Entity source;
-        protected final AttributeSensor<T> sensor;
-        protected final Predicate<? super T> predicate;
-        
-        public AttributeAndSensorCondition(Entity source, AttributeSensor<T> sensor, Predicate<? super T> predicate) {
-            this.source = checkNotNull(source, "source");
-            this.sensor = checkNotNull(sensor, "sensor");
-            this.predicate = checkNotNull(predicate, "predicate");
-        }
-    }
-    
-    public static ProtoBuilder builder() {
-        return new ProtoBuilder();
-    }
-    
-    /**
-     * Builder for producing variants of attributeWhenReady.
-     */
-    @Beta
-    public static class ProtoBuilder {
-        /**
-         * Will wait for the attribute on the given entity.
-         * If that entity reports {@link Lifecycle#ON_FIRE} for its {@link Attributes#SERVICE_STATE} then it will abort. 
-         */
-        public <T2> Builder<T2,T2> attributeWhenReady(Entity source, AttributeSensor<T2> sensor) {
-            return new Builder<T2,T2>(source, sensor).abortIfOnFire();
-        }
-
-        /**
-         * Will wait for the attribute on the given entity, not aborting when it goes {@link Lifecycle#ON_FIRE}.
-         */
-        public <T2> Builder<T2,T2> attributeWhenReadyAllowingOnFire(Entity source, AttributeSensor<T2> sensor) {
-            return new Builder<T2,T2>(source, sensor);
-        }
-
-        /** Constructs a builder for task for parallel execution returning a list of values of the given sensor list on the given entity, 
-         * optionally when the values satisfy a given readiness predicate (defaulting to groovy truth if not supplied) */ 
-        @Beta
-        public <T> MultiBuilder<T, T, List<T>> attributeWhenReadyFromMultiple(Iterable<? extends Entity> sources, AttributeSensor<T> sensor) {
-            return attributeWhenReadyFromMultiple(sources, sensor, GroovyJavaMethods.truthPredicate());
-        }
-        /** As {@link #attributeWhenReadyFromMultiple(Iterable, AttributeSensor)} with an explicit readiness test. */
-        @Beta
-        public <T> MultiBuilder<T, T, List<T>> attributeWhenReadyFromMultiple(Iterable<? extends Entity> sources, AttributeSensor<T> sensor, Predicate<? super T> readiness) {
-            return new MultiBuilder<T, T, List<T>>(sources, sensor, readiness);
-        }
-    }
-
-    /**
-     * Builder for producing variants of attributeWhenReady.
-     */
-    public static class Builder<T,V> {
-        protected Entity source;
-        protected AttributeSensor<T> sensor;
-        protected Predicate<? super T> readiness;
-        protected Function<? super T, ? extends V> postProcess;
-        protected List<AttributeAndSensorCondition<?>> abortSensorConditions = Lists.newArrayList();
-        protected String blockingDetails;
-        protected Duration timeout;
-        protected Maybe<V> onTimeout;
-        protected  boolean ignoreUnmanaged = WaitInTaskForAttributeReady.DEFAULT_IGNORE_UNMANAGED;
-        protected Maybe<V> onUnmanaged;
-
-        protected Builder(Entity source, AttributeSensor<T> sensor) {
-            this.source = source;
-            this.sensor = sensor;
-        }
-        
-        /**
-         * Will wait for the attribute on the given entity.
-         * If that entity report {@link Lifecycle#ON_FIRE} for its {@link Attributes#SERVICE_STATE_ACTUAL} then it will abort.
-         * @deprecated since 0.7.0 use {@link DependentConfiguration#builder()} then {@link ProtoBuilder#attributeWhenReady(Entity, AttributeSensor)} then {@link #abortIfOnFire()} 
-         */
-        @SuppressWarnings({ "unchecked", "rawtypes" })
-        public <T2> Builder<T2,T2> attributeWhenReady(Entity source, AttributeSensor<T2> sensor) {
-            this.source = checkNotNull(source, "source");
-            this.sensor = (AttributeSensor) checkNotNull(sensor, "sensor");
-            abortIfOnFire();
-            return (Builder<T2, T2>) this;
-        }
-        public Builder<T,V> readiness(Closure<Boolean> val) {
-            this.readiness = GroovyJavaMethods.predicateFromClosure(checkNotNull(val, "val"));
-            return this;
-        }
-        public Builder<T,V> readiness(Predicate<? super T> val) {
-            this.readiness = checkNotNull(val, "ready");
-            return this;
-        }
-        @SuppressWarnings({ "unchecked", "rawtypes" })
-        public <V2> Builder<T,V2> postProcess(Closure<V2> val) {
-            this.postProcess = (Function) GroovyJavaMethods.<T,V2>functionFromClosure(checkNotNull(val, "postProcess"));
-            return (Builder<T,V2>) this;
-        }
-        @SuppressWarnings({ "unchecked", "rawtypes" })
-        public <V2> Builder<T,V2> postProcess(final Function<? super T, V2>  val) {
-            this.postProcess = (Function) checkNotNull(val, "postProcess");
-            return (Builder<T,V2>) this;
-        }
-        public <T2> Builder<T,V> abortIf(Entity source, AttributeSensor<T2> sensor) {
-            return abortIf(source, sensor, GroovyJavaMethods.truthPredicate());
-        }
-        public <T2> Builder<T,V> abortIf(Entity source, AttributeSensor<T2> sensor, Predicate<? super T2> predicate) {
-            abortSensorConditions.add(new AttributeAndSensorCondition<T2>(source, sensor, predicate));
-            return this;
-        }
-        public Builder<T,V> abortIfOnFire() {
-            abortIf(source, Attributes.SERVICE_STATE_ACTUAL, Predicates.equalTo(Lifecycle.ON_FIRE));
-            return this;
-        }
-        public Builder<T,V> blockingDetails(String val) {
-            blockingDetails = val;
-            return this;
-        }
-        /** specifies an optional timeout; by default it waits forever, or until unmanaged or other abort condition */
-        public Builder<T,V> timeout(Duration val) {
-            timeout = val;
-            return this;
-        }
-        public Builder<T,V> onTimeoutReturn(V val) {
-            onTimeout = Maybe.of(val);
-            return this;
-        }
-        public Builder<T,V> onTimeoutThrow() {
-            onTimeout = Maybe.<V>absent();
-            return this;
-        }
-        public Builder<T,V> onUnmanagedReturn(V val) {
-            onUnmanaged = Maybe.of(val);
-            return this;
-        }
-        public Builder<T,V> onUnmanagedThrow() {
-            onUnmanaged = Maybe.<V>absent();
-            return this;
-        }
-        /** @since 0.7.0 included in case old behaviour of not checking whether the entity is managed is required
-         * (I can't see why it is; polling will likely give errors, once it is unmanaged this will never completed,
-         * and before management the current code will continue, so long as there are no other errors) */ @Deprecated
-        public Builder<T,V> onUnmanagedContinue() {
-            ignoreUnmanaged = true;
-            return this;
-        }
-        /** take advantage of the fact that this builder can build multiple times, allowing subclasses 
-         * to change the source along the way */
-        protected Builder<T,V> source(Entity source) {
-            this.source = source;
-            return this;
-        }
-        /** as {@link #source(Entity)} */
-        @SuppressWarnings({ "unchecked", "rawtypes" })
-        protected Builder<T,V> sensor(AttributeSensor<? extends T> sensor) {
-            this.sensor = (AttributeSensor) sensor;
-            return this;
-        }
-        public Task<V> build() {
-            validate();
-            
-            return Tasks.<V>builder().dynamic(false)
-                .name("waiting on "+sensor.getName())
-                .description("Waiting on sensor "+sensor.getName()+" from "+source)
-                .tag("attributeWhenReady")
-                .body(new WaitInTaskForAttributeReady<T,V>(this))
-                .build();
-        }
-        
-        public V runNow() {
-            validate();
-            return new WaitInTaskForAttributeReady<T,V>(this).call();
-        }
-        @SuppressWarnings({ "unchecked", "rawtypes" })
-        private void validate() {
-            checkNotNull(source, "Entity source");
-            checkNotNull(sensor, "Sensor");
-            if (readiness == null) readiness = GroovyJavaMethods.truthPredicate();
-            if (postProcess == null) postProcess = (Function) Functions.identity();
-        }
-    }
-
-    /**
-     * Builder for producing variants of attributeWhenReady.
-     */
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Beta
-    public static class MultiBuilder<T, V, V2> {
-        protected final String name;
-        protected final String descriptionBase;
-        protected final Builder<T,V> builder;
-        // if desired, the use of this multiSource could allow different conditions; 
-        // but probably an easier API just for the caller to build the parallel task  
-        protected final List<AttributeAndSensorCondition<?>> multiSource = Lists.newArrayList();
-        protected Function<? super List<V>, V2> postProcessFromMultiple;
-        
-        /** returns a task for parallel execution returning a list of values of the given sensor list on the given entity, 
-         * optionally when the values satisfy a given readiness predicate (defaulting to groovy truth if not supplied) */ 
-        @Beta
-        protected MultiBuilder(Iterable<? extends Entity> sources, AttributeSensor<T> sensor) {
-            this(sources, sensor, GroovyJavaMethods.truthPredicate());
-        }
-        @Beta
-        protected MultiBuilder(Iterable<? extends Entity> sources, AttributeSensor<T> sensor, Predicate<? super T> readiness) {
-            builder = new Builder<T,V>(null, sensor);
-            builder.readiness(readiness);
-            
-            for (Entity s : checkNotNull(sources, "sources")) {
-                multiSource.add(new AttributeAndSensorCondition<T>(s, sensor, readiness));
-            }
-            this.name = "waiting on "+sensor.getName();
-            this.descriptionBase = "waiting on "+sensor.getName()+" "+readiness
-                +" from "+Iterables.size(sources)+" entit"+Strings.ies(sources);
-        }
-        
-        /** Apply post-processing to the entire list of results */
-        public <V2b> MultiBuilder<T, V, V2b> postProcessFromMultiple(final Function<? super List<V>, V2b> val) {
-            this.postProcessFromMultiple = (Function) checkNotNull(val, "postProcessFromMulitple");
-            return (MultiBuilder<T,V, V2b>) this;
-        }
-        /** Apply post-processing to the entire list of results 
-         * See {@link CollectionFunctionals#all(Predicate)} and {@link CollectionFunctionals#quorum(org.apache.brooklyn.util.collections.QuorumCheck, Predicate)
-         * which allow useful arguments. */
-        public MultiBuilder<T, V, Boolean> postProcessFromMultiple(final Predicate<? super List<V>> val) {
-            return postProcessFromMultiple(Functions.forPredicate(val));
-        }
-        
-        public <V1> MultiBuilder<T, V1, V2> postProcess(Closure<V1> val) {
-            builder.postProcess(val);
-            return (MultiBuilder<T, V1, V2>) this;
-        }
-        public <V1> MultiBuilder<T, V1, V2> postProcess(final Function<? super T, V1>  val) {
-            builder.postProcess(val);
-            return (MultiBuilder<T, V1, V2>) this;
-        }
-        public <T2> MultiBuilder<T, V, V2> abortIf(Entity source, AttributeSensor<T2> sensor) {
-            builder.abortIf(source, sensor);
-            return this;
-        }
-        public <T2> MultiBuilder<T, V, V2> abortIf(Entity source, AttributeSensor<T2> sensor, Predicate<? super T2> predicate) {
-            builder.abortIf(source, sensor, predicate);
-            return this;
-        }
-        public MultiBuilder<T, V, V2> abortIfOnFire() {
-            builder.abortIfOnFire();
-            return this;
-        }
-        public MultiBuilder<T, V, V2> blockingDetails(String val) {
-            builder.blockingDetails(val);
-            return this;
-        }
-        public MultiBuilder<T, V, V2> timeout(Duration val) {
-            builder.timeout(val);
-            return this;
-        }
-        public MultiBuilder<T, V, V2> onTimeoutReturn(V val) {
-            builder.onTimeoutReturn(val);
-            return this;
-        }
-        public MultiBuilder<T, V, V2> onTimeoutThrow() {
-            builder.onTimeoutThrow();
-            return this;
-        }
-        public MultiBuilder<T, V, V2> onUnmanagedReturn(V val) {
-            builder.onUnmanagedReturn(val);
-            return this;
-        }
-        public MultiBuilder<T, V, V2> onUnmanagedThrow() {
-            builder.onUnmanagedThrow();
-            return this;
-        }
-        
-        public Task<V2> build() {
-            List<Task<V>> tasks = MutableList.of();
-            for (AttributeAndSensorCondition<?> source: multiSource) {
-                builder.source(source.source);
-                builder.sensor((AttributeSensor)source.sensor);
-                builder.readiness((Predicate)source.predicate);
-                tasks.add(builder.build());
-            }
-            final Task<List<V>> parallelTask = Tasks.<List<V>>builder().parallel(true).addAll(tasks)
-                .name(name)
-                .description(descriptionBase+
-                    (builder.timeout!=null ? ", timeout "+builder.timeout : ""))
-                .build();
-            
-            if (postProcessFromMultiple == null) {
-                // V2 should be the right type in normal operations
-                return (Task<V2>) parallelTask;
-            } else {
-                return Tasks.<V2>builder().name(name).description(descriptionBase)
-                    .tag("attributeWhenReady")
-                    .body(new Callable<V2>() {
-                        @Override public V2 call() throws Exception {
-                            List<V> prePostProgress = DynamicTasks.queue(parallelTask).get();
-                            return DynamicTasks.queue(
-                                Tasks.<V2>builder().name("post-processing").description("Applying "+postProcessFromMultiple)
-                                    .body(Functionals.callable(postProcessFromMultiple, prePostProgress))
-                                    .build()).get();
-                        }
-                    })
-                    .build();
-            }
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/core/HttpRequestSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/HttpRequestSensor.java b/core/src/main/java/org/apache/brooklyn/sensor/core/HttpRequestSensor.java
deleted file mode 100644
index 6b9c780..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/core/HttpRequestSensor.java
+++ /dev/null
@@ -1,96 +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.core;
-
-import java.net.URI;
-
-import net.minidev.json.JSONObject;
-
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.effector.AddSensor;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Functions;
-import com.google.common.base.Supplier;
-
-/**
- * Configurable {@link org.apache.brooklyn.api.entity.EntityInitializer} which adds an HTTP sensor feed to retrieve the
- * {@link JSONObject} from a JSON response in order to populate the sensor with the data at the {@code jsonPath}.
- *
- * @see SshCommandSensor
- * @see JmxAttributeSensor
- */
-@Beta
-public final class HttpRequestSensor<T> extends AddSensor<T> {
-
-    private static final Logger LOG = LoggerFactory.getLogger(HttpRequestSensor.class);
-
-    public static final ConfigKey<String> SENSOR_URI = ConfigKeys.newStringConfigKey("uri", "HTTP URI to poll for JSON");
-    public static final ConfigKey<String> JSON_PATH = ConfigKeys.newStringConfigKey("jsonPath", "JSON path to select in HTTP response; default $", "$");
-    public static final ConfigKey<String> USERNAME = ConfigKeys.newStringConfigKey("username", "Username for HTTP request, if required");
-    public static final ConfigKey<String> PASSWORD = ConfigKeys.newStringConfigKey("password", "Password for HTTP request, if required");
-
-    protected final Supplier<URI> uri;
-    protected final String jsonPath;
-    protected final String username;
-    protected final String password;
-
-    public HttpRequestSensor(final ConfigBag params) {
-        super(params);
-
-        uri = new Supplier<URI>() {
-            @Override
-            public URI get() {
-                return URI.create(params.get(SENSOR_URI));
-            }
-        };
-        jsonPath = params.get(JSON_PATH);
-        username = params.get(USERNAME);
-        password = params.get(PASSWORD);
-    }
-
-    @Override
-    public void apply(final EntityLocal entity) {
-        super.apply(entity);
-
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("Adding HTTP JSON sensor {} to {}", name, entity);
-        }
-
-        HttpPollConfig<T> pollConfig = new HttpPollConfig<T>(sensor)
-                .checkSuccess(HttpValueFunctions.responseCodeEquals(200))
-                .onFailureOrException(Functions.constant((T) null))
-                .onSuccess(HttpValueFunctions.<T>jsonContentsFromPath(jsonPath))
-                .period(period);
-
-        HttpFeed.builder().entity(entity)
-                .baseUri(uri)
-                .credentialsIfNotNull(username, password)
-                .poll(pollConfig)
-                .build();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/core/PortAttributeSensorAndConfigKey.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/PortAttributeSensorAndConfigKey.java b/core/src/main/java/org/apache/brooklyn/sensor/core/PortAttributeSensorAndConfigKey.java
deleted file mode 100644
index e269966..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/core/PortAttributeSensorAndConfigKey.java
+++ /dev/null
@@ -1,141 +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.core;
-
-import java.util.Collection;
-import java.util.Iterator;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.location.MachineProvisioningLocation;
-import org.apache.brooklyn.api.location.PortRange;
-import org.apache.brooklyn.api.location.PortSupplier;
-import org.apache.brooklyn.api.mgmt.ManagementContext;
-import org.apache.brooklyn.api.sensor.Sensor;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
-import org.apache.brooklyn.core.internal.BrooklynInitialization;
-import org.apache.brooklyn.core.location.Locations;
-import org.apache.brooklyn.util.core.flags.TypeCoercions;
-import org.apache.brooklyn.util.guava.Maybe;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Predicates;
-import com.google.common.collect.Iterables;
-
-/**
- * A {@link Sensor} describing a port on a system,
- * with a {@link ConfigKey} which can be configured with a port range
- * (either a number e.g. 80, or a string e.g. "80" or "8080-8089" or even "80, 8080-8089, 8800+", or a list of these).
- * <p>
- * To convert at runtime a single port is chosen, respecting the entity.
- */
-public class PortAttributeSensorAndConfigKey extends AttributeSensorAndConfigKey<PortRange,Integer> {
-
-    private static final long serialVersionUID = 4680651022807491321L;
-
-    public static final Logger LOG = LoggerFactory.getLogger(PortAttributeSensorAndConfigKey.class);
-
-    static { BrooklynInitialization.initAll(); }
-
-    public PortAttributeSensorAndConfigKey(String name) {
-        this(name, name, null);
-    }
-    public PortAttributeSensorAndConfigKey(String name, String description) {
-        this(name, description, null);
-    }
-    public PortAttributeSensorAndConfigKey(String name, String description, Object defaultValue) {
-        super(PortRange.class, Integer.class, name, description, defaultValue);
-    }
-    public PortAttributeSensorAndConfigKey(PortAttributeSensorAndConfigKey orig, Object defaultValue) {
-        super(orig, TypeCoercions.coerce(defaultValue, PortRange.class));
-    }
-    @Override
-    protected Integer convertConfigToSensor(PortRange value, Entity entity) {
-        if (value==null) return null;
-        Collection<? extends Location> locations = entity.getLocations();
-        if (!locations.isEmpty()) {
-            Maybe<? extends Location> lo = Locations.findUniqueMachineLocation(locations);
-            if (!lo.isPresent()) {
-                // Try a unique location which isn't a machine provisioner
-                Iterator<? extends Location> li = Iterables.filter(locations,
-                        Predicates.not(Predicates.instanceOf(MachineProvisioningLocation.class))).iterator();
-                if (li.hasNext()) lo = Maybe.of(li.next());
-                if (li.hasNext()) lo = Maybe.absent();
-            }
-            // Fall back to selecting the single location
-            if (!lo.isPresent() && locations.size() == 1) {
-                lo = Maybe.of(locations.iterator().next());
-            }
-            if (LOG.isTraceEnabled()) {
-                LOG.trace("Convert config to sensor for {} found locations: {}. Selected: {}", new Object[] {entity, locations, lo});
-            }
-            if (lo.isPresent()) {
-                Location l = lo.get();
-                Optional<Boolean> locationRunning = Optional.fromNullable(l.getConfig(BrooklynConfigKeys.SKIP_ENTITY_START_IF_RUNNING));
-                Optional<Boolean> entityRunning = Optional.fromNullable(entity.getConfig(BrooklynConfigKeys.SKIP_ENTITY_START_IF_RUNNING));
-                Optional<Boolean> locationInstalled = Optional.fromNullable(l.getConfig(BrooklynConfigKeys.SKIP_ENTITY_INSTALLATION));
-                Optional<Boolean> entityInstalled = Optional.fromNullable(entity.getConfig(BrooklynConfigKeys.SKIP_ENTITY_INSTALLATION));
-                Optional<Boolean> entityStarted = Optional.fromNullable(entity.getConfig(BrooklynConfigKeys.SKIP_ENTITY_START));
-                boolean skipCheck = locationRunning.or(entityRunning).or(locationInstalled).or(entityInstalled).or(entityStarted).or(false);
-                if (l instanceof PortSupplier) {
-                    int p = ((PortSupplier) l).obtainPort(value);
-                    if (p != -1) {
-                        LOG.debug("{}: choosing port {} for {}", new Object[] { entity, p, getName() });
-                        return p;
-                    }
-                    // If we are not skipping install or already started, fail now
-                    if (!skipCheck) {
-                        int rangeSize = Iterables.size(value);
-                        if (rangeSize == 0) {
-                            LOG.warn("{}: no port available for {} (empty range {})", new Object[] { entity, getName(), value });
-                        } else if (rangeSize == 1) {
-                            Integer pp = value.iterator().next();
-                            if (pp > 1024) {
-                                LOG.warn("{}: port {} not available for {}", new Object[] { entity, pp, getName() });
-                            } else {
-                                LOG.warn("{}: port {} not available for {} (root may be required?)", new Object[] { entity, pp, getName() });
-                            }
-                        } else {
-                            LOG.warn("{}: no port available for {} (tried range {})", new Object[] { entity, getName(), value });
-                        }
-                        return null; // Definitively, no ports available
-                    }
-                }
-                // Ports may be available, we just can't tell from the location
-                Integer v = (value.isEmpty() ? null : value.iterator().next());
-                LOG.debug("{}: choosing port {} (unconfirmed) for {}", new Object[] { entity, v, getName() });
-                return v;
-            } else {
-                LOG.warn("{}: ports not applicable, or not yet applicable, because has multiple locations {}; ignoring ", new Object[] { entity, locations, getName() });
-            }
-        } else {
-            LOG.warn("{}: ports not applicable, or not yet applicable, bacause has no locations; ignoring {}", entity, getName());
-        }
-        return null;
-    }
-
-    @Override
-    protected Integer convertConfigToSensor(PortRange value, ManagementContext managementContext) {
-        LOG.warn("ports not applicable, because given managementContext rather than entity; ignoring {}", getName());
-        return null;
-    }
-}


[21/36] incubator-brooklyn git commit: Rename o.a.b.sensor.feed to o.a.b.feed and o.a.b.core.feed

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/sensor/feed/http/JsonFunctionsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/feed/http/JsonFunctionsTest.java b/core/src/test/java/org/apache/brooklyn/sensor/feed/http/JsonFunctionsTest.java
deleted file mode 100644
index 41201af..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/feed/http/JsonFunctionsTest.java
+++ /dev/null
@@ -1,130 +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.feed.http;
-
-import java.util.NoSuchElementException;
-
-import org.apache.brooklyn.sensor.feed.http.JsonFunctions;
-import org.apache.brooklyn.util.collections.Jsonya;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.collections.Jsonya.Navigator;
-import org.apache.brooklyn.util.guava.Functionals;
-import org.apache.brooklyn.util.guava.Maybe;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import com.google.gson.JsonElement;
-import com.google.gson.JsonParser;
-import com.jayway.jsonpath.PathNotFoundException;
-
-public class JsonFunctionsTest {
-
-    public static JsonElement europeMap() {
-        Navigator<MutableMap<Object, Object>> europe = Jsonya.newInstance().at("europe", "uk", "edinburgh")
-                .put("population", 500*1000)
-                .put("weather", "wet", "lighting", "dark")
-                .root().at("europe").at("france").put("population", 80*1000*1000)
-                .root();
-        return new JsonParser().parse( europe.toString() );
-    }
-
-    @Test
-    public void testWalk1() {
-        JsonElement pop = JsonFunctions.walk("europe", "france", "population").apply(europeMap());
-        Assert.assertEquals( (int)JsonFunctions.cast(Integer.class).apply(pop), 80*1000*1000 );
-    }
-
-    @Test
-    public void testWalk2() {
-        String weather = Functionals.chain(
-            JsonFunctions.walk("europe.uk.edinburgh.weather"),
-            JsonFunctions.cast(String.class) ).apply(europeMap());
-        Assert.assertEquals(weather, "wet");
-    }
-
-    @Test(expectedExceptions=NoSuchElementException.class)
-    public void testWalkWrong() {
-        Functionals.chain(
-            JsonFunctions.walk("europe", "spain", "barcelona"),
-            JsonFunctions.cast(String.class) ).apply(europeMap());
-    }
-
-
-    @Test
-    public void testWalkM() {
-        Maybe<JsonElement> pop = JsonFunctions.walkM("europe", "france", "population").apply( Maybe.of(europeMap()) );
-        Assert.assertEquals( (int)JsonFunctions.castM(Integer.class).apply(pop), 80*1000*1000 );
-    }
-
-    @Test
-    public void testWalkMWrong1() {
-        Maybe<JsonElement> m = JsonFunctions.walkM("europe", "spain", "barcelona").apply( Maybe.of( europeMap()) );
-        Assert.assertTrue(m.isAbsent());
-    }
-
-    @Test(expectedExceptions=Exception.class)
-    public void testWalkMWrong2() {
-        Maybe<JsonElement> m = JsonFunctions.walkM("europe", "spain", "barcelona").apply( Maybe.of( europeMap()) );
-        JsonFunctions.castM(String.class).apply(m);
-    }
-
-    
-    @Test
-    public void testWalkN() {
-        JsonElement pop = JsonFunctions.walkN("europe", "france", "population").apply( europeMap() );
-        Assert.assertEquals( (int)JsonFunctions.cast(Integer.class).apply(pop), 80*1000*1000 );
-    }
-
-    @Test
-    public void testWalkNWrong1() {
-        JsonElement m = JsonFunctions.walkN("europe", "spain", "barcelona").apply( europeMap() );
-        Assert.assertNull(m);
-    }
-
-    public void testWalkNWrong2() {
-        JsonElement m = JsonFunctions.walkN("europe", "spain", "barcelona").apply( europeMap() );
-        String n = JsonFunctions.cast(String.class).apply(m);
-        Assert.assertNull(n);
-    }
-
-    @Test
-    public void testGetPath1(){
-        Integer obj = (Integer) JsonFunctions.getPath("$.europe.uk.edinburgh.population").apply(europeMap());
-        Assert.assertEquals((int) obj, 500*1000);
-    }
-
-    @Test
-    public void testGetPath2(){
-        String obj = (String) JsonFunctions.getPath("$.europe.uk.edinburgh.lighting").apply(europeMap());
-        Assert.assertEquals(obj, "dark");
-    }
-
-    @Test
-    public void testGetMissingPathIsNullOrThrows(){
-        try {
-            // TODO is there a way to force this to return null if not found?
-            // for me (Alex) it throws but for others it seems to return null
-            Object obj = JsonFunctions.getPath("$.europe.spain.malaga").apply(europeMap());
-            Assert.assertNull(obj);
-        } catch (PathNotFoundException e) {
-            // not unexpected
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/sensor/feed/shell/ShellFeedIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/feed/shell/ShellFeedIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/sensor/feed/shell/ShellFeedIntegrationTest.java
deleted file mode 100644
index b274cbc..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/feed/shell/ShellFeedIntegrationTest.java
+++ /dev/null
@@ -1,226 +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.feed.shell;
-
-import static org.testng.Assert.assertTrue;
-
-import java.util.Arrays;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.core.entity.EntityInternal.FeedSupport;
-import org.apache.brooklyn.core.sensor.Sensors;
-import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.feed.function.FunctionFeedTest;
-import org.apache.brooklyn.sensor.feed.shell.ShellFeed;
-import org.apache.brooklyn.sensor.feed.shell.ShellFeedIntegrationTest;
-import org.apache.brooklyn.sensor.feed.shell.ShellPollConfig;
-import org.apache.brooklyn.sensor.feed.ssh.SshPollValue;
-import org.apache.brooklyn.sensor.feed.ssh.SshValueFunctions;
-import org.apache.brooklyn.test.Asserts;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.apache.brooklyn.util.stream.Streams;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
-
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-public class ShellFeedIntegrationTest extends BrooklynAppUnitTestSupport {
-
-    private static final Logger log = LoggerFactory.getLogger(ShellFeedIntegrationTest.class);
-    
-    final static AttributeSensor<String> SENSOR_STRING = Sensors.newStringSensor("aString", "");
-    final static AttributeSensor<Integer> SENSOR_INT = Sensors.newIntegerSensor("anInt", "");
-    final static AttributeSensor<Long> SENSOR_LONG = Sensors.newLongSensor("aLong", "");
-
-    private LocalhostMachineProvisioningLocation loc;
-    private EntityLocal entity;
-    private ShellFeed feed;
-    
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        loc = new LocalhostMachineProvisioningLocation();
-        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        app.start(ImmutableList.of(loc));
-    }
-
-    @AfterMethod(alwaysRun=true)
-    @Override
-    public void tearDown() throws Exception {
-        if (feed != null) feed.stop();
-        super.tearDown();
-        if (loc != null) Streams.closeQuietly(loc);
-    }
-    
-    @Test(groups="Integration")
-    public void testReturnsShellExitStatus() throws Exception {
-        feed = ShellFeed.builder()
-                .entity(entity)
-                .poll(new ShellPollConfig<Integer>(SENSOR_INT)
-                        .command("exit 123")
-                        .onFailure(SshValueFunctions.exitStatus()))
-                .build();
-
-        EntityTestUtils.assertAttributeEqualsEventually(entity, SENSOR_INT, 123);
-    }
-    
-    @Test(groups="Integration")
-    public void testFeedDeDupe() throws Exception {
-        testReturnsShellExitStatus();
-        entity.addFeed(feed);
-        log.info("Feed 0 is: "+feed);
-        
-        testReturnsShellExitStatus();
-        log.info("Feed 1 is: "+feed);
-        entity.addFeed(feed);
-                
-        FeedSupport feeds = ((EntityInternal)entity).feeds();
-        Assert.assertEquals(feeds.getFeeds().size(), 1, "Wrong feed count: "+feeds.getFeeds());
-    }
-    
-    // TODO timeout no longer supported; would be nice to have a generic task-timeout feature,
-    // now that the underlying impl uses SystemProcessTaskFactory
-    @Test(enabled=false, groups={"Integration", "WIP"})
-    public void testShellTimesOut() throws Exception {
-        feed = ShellFeed.builder()
-                .entity(entity)
-                .poll(new ShellPollConfig<String>(SENSOR_STRING)
-                        .command("sleep 10")
-                        .timeout(1, TimeUnit.MILLISECONDS)
-                        .onException(new FunctionFeedTest.ToStringFunction()))
-                .build();
-
-        Asserts.succeedsEventually(new Runnable() {
-            public void run() {
-                String val = entity.getAttribute(SENSOR_STRING);
-                assertTrue(val != null && val.contains("timed out after 1ms"), "val=" + val);
-            }});
-    }
-    
-    @Test(groups="Integration")
-    public void testShellUsesEnv() throws Exception {
-        feed = ShellFeed.builder()
-                .entity(entity)
-                .poll(new ShellPollConfig<String>(SENSOR_STRING)
-                        .env(ImmutableMap.of("MYENV", "MYVAL"))
-                        .command("echo hello $MYENV")
-                        .onSuccess(SshValueFunctions.stdout()))
-                .build();
-        
-        Asserts.succeedsEventually(new Runnable() {
-            public void run() {
-                String val = entity.getAttribute(SENSOR_STRING);
-                assertTrue(val != null && val.contains("hello MYVAL"), "val="+val);
-            }});
-    }
-    
-    @Test(groups="Integration")
-    public void testReturnsShellStdout() throws Exception {
-        feed = ShellFeed.builder()
-                .entity(entity)
-                .poll(new ShellPollConfig<String>(SENSOR_STRING)
-                        .command("echo hello")
-                        .onSuccess(SshValueFunctions.stdout()))
-                .build();
-        
-        Asserts.succeedsEventually(new Runnable() {
-            public void run() {
-                String val = entity.getAttribute(SENSOR_STRING);
-                assertTrue(val != null && val.contains("hello"), "val="+val);
-            }});
-    }
-
-    @Test(groups="Integration")
-    public void testReturnsShellStderr() throws Exception {
-        final String cmd = "thiscommanddoesnotexist";
-        
-        feed = ShellFeed.builder()
-                .entity(entity)
-                .poll(new ShellPollConfig<String>(SENSOR_STRING)
-                        .command(cmd)
-                        .onFailure(SshValueFunctions.stderr()))
-                .build();
-        
-        Asserts.succeedsEventually(new Runnable() {
-            public void run() {
-                String val = entity.getAttribute(SENSOR_STRING);
-                assertTrue(val != null && val.contains(cmd), "val="+val);
-            }});
-    }
-    
-    @Test(groups="Integration")
-    public void testFailsOnNonZero() throws Exception {
-        feed = ShellFeed.builder()
-                .entity(entity)
-                .poll(new ShellPollConfig<String>(SENSOR_STRING)
-                        .command("exit 123")
-                        .onSuccess(new Function<SshPollValue, String>() {
-                            @Override
-                            public String apply(SshPollValue input) {
-                                return "Exit status (on success) " + input.getExitStatus();
-                            }})
-                        .onFailure(new Function<SshPollValue, String>() {
-                            @Override
-                            public String apply(SshPollValue input) {
-                                return "Exit status (on failure) " + input.getExitStatus();
-                            }}))
-                .build();
-        
-        Asserts.succeedsEventually(new Runnable() {
-            public void run() {
-                String val = entity.getAttribute(SENSOR_STRING);
-                assertTrue(val != null && val.contains("Exit status (on failure) 123"), "val="+val);
-            }});
-    }
-    
-    // Example in ShellFeed javadoc
-    @Test(groups="Integration")
-    public void testDiskUsage() throws Exception {
-        feed = ShellFeed.builder()
-                .entity(entity)
-                .poll(new ShellPollConfig<Long>(SENSOR_LONG)
-                        .command("df -P | tail -1")
-                        .onSuccess(new Function<SshPollValue, Long>() {
-                            public Long apply(SshPollValue input) {
-                                String[] parts = input.getStdout().split("[ \\t]+");
-                                System.out.println("input="+input+"; parts="+Arrays.toString(parts));
-                                return Long.parseLong(parts[2]);
-                            }}))
-                .build();
-        
-        Asserts.succeedsEventually(new Runnable() {
-            public void run() {
-                Long val = entity.getAttribute(SENSOR_LONG);
-                assertTrue(val != null && val >= 0, "val="+val);
-            }});
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/sensor/feed/ssh/SshFeedIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/feed/ssh/SshFeedIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/sensor/feed/ssh/SshFeedIntegrationTest.java
deleted file mode 100644
index de9d5f1..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/feed/ssh/SshFeedIntegrationTest.java
+++ /dev/null
@@ -1,264 +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.feed.ssh;
-
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.brooklyn.api.entity.EntityInitializer;
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.core.entity.Attributes;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.core.entity.EntityInternal.FeedSupport;
-import org.apache.brooklyn.core.sensor.Sensors;
-import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.feed.ssh.SshFeed;
-import org.apache.brooklyn.sensor.feed.ssh.SshFeedIntegrationTest;
-import org.apache.brooklyn.sensor.feed.ssh.SshPollConfig;
-import org.apache.brooklyn.sensor.feed.ssh.SshPollValue;
-import org.apache.brooklyn.sensor.feed.ssh.SshValueFunctions;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.stream.Streams;
-import org.apache.brooklyn.util.text.StringFunctions;
-import org.apache.brooklyn.util.text.StringPredicates;
-import org.apache.brooklyn.util.time.Duration;
-import org.apache.brooklyn.util.time.Time;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
-import org.apache.brooklyn.location.ssh.SshMachineLocation;
-
-import com.google.common.base.Function;
-import com.google.common.base.Predicates;
-import com.google.common.base.Supplier;
-import com.google.common.collect.ImmutableList;
-
-public class SshFeedIntegrationTest extends BrooklynAppUnitTestSupport {
-
-    private static final Logger log = LoggerFactory.getLogger(SshFeedIntegrationTest.class);
-    
-    final static AttributeSensor<String> SENSOR_STRING = Sensors.newStringSensor("aString", "");
-    final static AttributeSensor<Integer> SENSOR_INT = Sensors.newIntegerSensor("aLong", "");
-
-    private LocalhostMachineProvisioningLocation loc;
-    private SshMachineLocation machine;
-    private EntityLocal entity;
-    private SshFeed feed;
-    
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        loc = app.newLocalhostProvisioningLocation();
-        machine = loc.obtain();
-        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        app.start(ImmutableList.of(loc));
-    }
-
-    @AfterMethod(alwaysRun=true)
-    @Override
-    public void tearDown() throws Exception {
-        if (feed != null) feed.stop();
-        super.tearDown();
-        if (loc != null) Streams.closeQuietly(loc);
-    }
-    
-    /** this is one of the most common pattern */
-    @Test(groups="Integration")
-    public void testReturnsSshStdoutAndInfersMachine() throws Exception {
-        final TestEntity entity2 = app.createAndManageChild(EntitySpec.create(TestEntity.class)
-            // inject the machine location, because the app was started with a provisioning location
-            // and TestEntity doesn't provision
-            .location(machine));
-        
-        feed = SshFeed.builder()
-                .entity(entity2)
-                .poll(new SshPollConfig<String>(SENSOR_STRING)
-                        .command("echo hello")
-                        .onSuccess(SshValueFunctions.stdout()))
-                .build();
-        
-        EntityTestUtils.assertAttributeEventuallyNonNull(entity2, SENSOR_STRING);
-        String val = entity2.getAttribute(SENSOR_STRING);
-        Assert.assertTrue(val.contains("hello"), "val="+val);
-        Assert.assertEquals(val.trim(), "hello");
-    }
-
-    @Test(groups="Integration")
-    public void testFeedDeDupe() throws Exception {
-        testReturnsSshStdoutAndInfersMachine();
-        entity.addFeed(feed);
-        log.info("Feed 0 is: "+feed);
-        
-        testReturnsSshStdoutAndInfersMachine();
-        log.info("Feed 1 is: "+feed);
-        entity.addFeed(feed);
-                
-        FeedSupport feeds = ((EntityInternal)entity).feeds();
-        Assert.assertEquals(feeds.getFeeds().size(), 1, "Wrong feed count: "+feeds.getFeeds());
-    }
-    
-    @Test(groups="Integration")
-    public void testReturnsSshExitStatus() throws Exception {
-        feed = SshFeed.builder()
-                .entity(entity)
-                .machine(machine)
-                .poll(new SshPollConfig<Integer>(SENSOR_INT)
-                        .command("exit 123")
-                        .checkSuccess(Predicates.alwaysTrue())
-                        .onSuccess(SshValueFunctions.exitStatus()))
-                .build();
-
-        EntityTestUtils.assertAttributeEqualsEventually(entity, SENSOR_INT, 123);
-    }
-    
-    @Test(groups="Integration")
-    public void testReturnsSshStdout() throws Exception {
-        feed = SshFeed.builder()
-                .entity(entity)
-                .machine(machine)
-                .poll(new SshPollConfig<String>(SENSOR_STRING)
-                        .command("echo hello")
-                        .onSuccess(SshValueFunctions.stdout()))
-                .build();
-        
-        EntityTestUtils.assertAttributeEventually(entity, SENSOR_STRING, 
-            Predicates.compose(Predicates.equalTo("hello"), StringFunctions.trim()));
-    }
-
-    @Test(groups="Integration")
-    public void testReturnsSshStderr() throws Exception {
-        final String cmd = "thiscommanddoesnotexist";
-        
-        feed = SshFeed.builder()
-                .entity(entity)
-                .machine(machine)
-                .poll(new SshPollConfig<String>(SENSOR_STRING)
-                        .command(cmd)
-                        .onFailure(SshValueFunctions.stderr()))
-                .build();
-        
-        EntityTestUtils.assertAttributeEventually(entity, SENSOR_STRING, StringPredicates.containsLiteral(cmd));
-    }
-    
-    @Test(groups="Integration")
-    public void testFailsOnNonZero() throws Exception {
-        feed = SshFeed.builder()
-                .entity(entity)
-                .machine(machine)
-                .poll(new SshPollConfig<String>(SENSOR_STRING)
-                        .command("exit 123")
-                        .onFailure(new Function<SshPollValue, String>() {
-                            @Override
-                            public String apply(SshPollValue input) {
-                                return "Exit status " + input.getExitStatus();
-                            }}))
-                .build();
-        
-        EntityTestUtils.assertAttributeEventually(entity, SENSOR_STRING, StringPredicates.containsLiteral("Exit status 123"));
-    }
-    
-    @Test(groups="Integration")
-    public void testAddedEarly() throws Exception {
-        final TestEntity entity2 = app.addChild(EntitySpec.create(TestEntity.class)
-            .location(machine)
-            .addInitializer(new EntityInitializer() {
-                @Override
-                public void apply(EntityLocal entity) {
-                    SshFeed.builder()
-                        .entity(entity)
-                        .onlyIfServiceUp()
-                        .poll(new SshPollConfig<String>(SENSOR_STRING)
-                            .command("echo hello")
-                            .onSuccess(SshValueFunctions.stdout()))
-                        .build();
-                }
-            }));
-        Time.sleep(Duration.seconds(2));
-        // would be nice to hook in and assert no errors
-        Assert.assertEquals(entity2.getAttribute(SENSOR_STRING), null);
-        Entities.manage(entity2);
-        Time.sleep(Duration.seconds(2));
-        Assert.assertEquals(entity2.getAttribute(SENSOR_STRING), null);
-        entity2.setAttribute(Attributes.SERVICE_UP, true);
-    
-        EntityTestUtils.assertAttributeEventually(entity2, SENSOR_STRING, StringPredicates.containsLiteral("hello"));
-    }
-
-    
-    @Test(groups="Integration")
-    public void testDynamicEnvAndCommandSupplier() throws Exception {
-        final TestEntity entity2 = app.createAndManageChild(EntitySpec.create(TestEntity.class).location(machine));
-        
-        final AtomicInteger count = new AtomicInteger();
-        Supplier<Map<String, String>> envSupplier = new Supplier<Map<String,String>>() {
-            @Override
-            public Map<String, String> get() {
-                return MutableMap.of("COUNT", ""+count.incrementAndGet());
-            }
-        };
-        Supplier<String> cmdSupplier = new Supplier<String>() {
-            @Override
-            public String get() {
-                return "echo count-"+count.incrementAndGet()+"-$COUNT";
-            }
-        };
-        
-        feed = SshFeed.builder()
-                .entity(entity2)
-                .poll(new SshPollConfig<String>(SENSOR_STRING)
-                        .env(envSupplier)
-                        .command(cmdSupplier)
-                        .onSuccess(SshValueFunctions.stdout()))
-                .build();
-        
-        EntityTestUtils.assertAttributeEventuallyNonNull(entity2, SENSOR_STRING);        
-        final String val1 = assertDifferentOneInOutput(entity2);
-        
-        EntityTestUtils.assertAttributeEventually(entity2, SENSOR_STRING, Predicates.not(Predicates.equalTo(val1)));        
-        final String val2 = assertDifferentOneInOutput(entity2);
-        log.info("vals from dynamic sensors are: "+val1.trim()+" and "+val2.trim());
-    }
-
-    private String assertDifferentOneInOutput(final TestEntity entity2) {
-        String val = entity2.getAttribute(SENSOR_STRING);
-        Assert.assertTrue(val.startsWith("count"), "val="+val);
-        try {
-            String[] fields = val.trim().split("-");
-            int field1 = Integer.parseInt(fields[1]); 
-            int field2 = Integer.parseInt(fields[2]);
-            Assert.assertEquals(Math.abs(field2-field1), 1, "expected difference of 1");
-        } catch (Throwable t) {
-            Exceptions.propagateIfFatal(t);
-            Assert.fail("Wrong output from sensor, got '"+val.trim()+"', giving error: "+t);
-        }
-        return val;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeedLiveTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeedLiveTest.java b/core/src/test/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeedLiveTest.java
deleted file mode 100644
index 42a25c0..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeedLiveTest.java
+++ /dev/null
@@ -1,104 +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.feed.windows;
-
-import java.util.Map;
-
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.location.MachineLocation;
-import org.apache.brooklyn.api.location.MachineProvisioningLocation;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.core.sensor.Sensors;
-import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.feed.windows.WindowsPerformanceCounterFeed;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-/**
- * WindowsPerformanceCounterFeed Live Test.
- * <p>
- * This test is currently disabled. To run, you must configure a location named {@code WindowsLiveTest}
- * or adapt the {@link #LOCATION_SPEC} below.
- * <p>
- * The location must provide Windows nodes that are running an SSH server on port 22. The login credentials must
- * be either be auto-detectable or configured in brooklyn.properties in the usual fashion.
- * <p>
- * Here is an example configuration from brooklyn.properties for a pre-configured Windows VM
- * running an SSH server with public key authentication:
- * <pre>
- * {@code brooklyn.location.named.WindowsLiveTest=byon:(hosts="ec2-xx-xxx-xxx-xx.eu-west-1.compute.amazonaws.com")
- * brooklyn.location.named.WindowsLiveTest.user=Administrator
- * brooklyn.location.named.WindowsLiveTest.privateKeyFile = ~/.ssh/id_rsa
- * brooklyn.location.named.WindowsLiveTest.publicKeyFile = ~/.ssh/id_rsa.pub
- * }</pre>
- * The location must by {@code byon} or another primitive type. Unfortunately, it's not possible to
- * use a jclouds location, as adding a dependency on brooklyn-locations-jclouds would cause a
- * cyclic dependency.
- */
-public class WindowsPerformanceCounterFeedLiveTest extends BrooklynAppLiveTestSupport {
-
-    final static AttributeSensor<Double> CPU_IDLE_TIME = Sensors.newDoubleSensor("cpu.idleTime", "");
-    final static AttributeSensor<Integer> TELEPHONE_LINES = Sensors.newIntegerSensor("telephone.lines", "");
-
-    private static final String LOCATION_SPEC = "named:WindowsLiveTest";
-
-    private Location loc;
-    private EntityLocal entity;
-
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() throws Exception {
-        super.setUp();
-        
-        Map<String,?> allFlags = MutableMap.<String,Object>builder()
-                .put("tags", ImmutableList.of(getClass().getName()))
-                .build();
-        MachineProvisioningLocation<? extends MachineLocation> provisioningLocation =
-                (MachineProvisioningLocation<? extends MachineLocation>)
-                        mgmt.getLocationRegistry().resolve(LOCATION_SPEC, allFlags);
-        loc = provisioningLocation.obtain(ImmutableMap.of());
-
-        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        app.start(ImmutableList.of(loc));
-    }
-
-    @Test(groups={"Live","Disabled"}, enabled=false)
-    public void testRetrievesPerformanceCounters() throws Exception {
-        // We can be pretty sure that a Windows instance in the cloud will have zero telephone lines...
-        entity.setAttribute(TELEPHONE_LINES, 42);
-        WindowsPerformanceCounterFeed feed = WindowsPerformanceCounterFeed.builder()
-                .entity(entity)
-                .addSensor("\\Processor(_total)\\% Idle Time", CPU_IDLE_TIME)
-                .addSensor("\\Telephony\\Lines", TELEPHONE_LINES)
-                .build();
-        try {
-            EntityTestUtils.assertAttributeEqualsEventually(entity, TELEPHONE_LINES, 0);
-        } finally {
-            feed.stop();
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeedTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeedTest.java b/core/src/test/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeedTest.java
deleted file mode 100644
index 9a27e8e..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeedTest.java
+++ /dev/null
@@ -1,132 +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.feed.windows;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertNull;
-import static org.testng.Assert.assertTrue;
-
-import java.util.Collection;
-import java.util.Iterator;
-
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.core.sensor.Sensors;
-import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.feed.windows.WindowsPerformanceCounterFeed;
-import org.apache.brooklyn.sensor.feed.windows.WindowsPerformanceCounterPollConfig;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.apache.brooklyn.util.text.Strings;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
-
-import io.cloudsoft.winrm4j.winrm.WinRmToolResponse;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-
-public class WindowsPerformanceCounterFeedTest extends BrooklynAppUnitTestSupport {
-
-    private Location loc;
-    private EntityLocal entity;
-
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        loc = new LocalhostMachineProvisioningLocation();
-        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        app.start(ImmutableList.of(loc));
-    }
-
-    @AfterMethod(alwaysRun=true)
-    @Override
-    public void tearDown() throws Exception {
-        super.tearDown();
-    }
-
-    private static final Logger log = LoggerFactory.getLogger(WindowsPerformanceCounterFeedTest.class);
-
-    @Test
-    public void testIteratorWithSingleValue() {
-        Iterator<?> iterator = new WindowsPerformanceCounterFeed
-                .PerfCounterValueIterator("\"10/14/2013 15:28:24.406\",\"0.000000\"");
-        assertTrue(iterator.hasNext());
-        assertEquals(iterator.next(), "0.000000");
-        assertFalse(iterator.hasNext());
-    }
-
-    @Test
-    public void testIteratorWithMultipleValues() {
-        Iterator<?> iterator = new WindowsPerformanceCounterFeed
-                .PerfCounterValueIterator("\"10/14/2013 15:35:50.582\",\"8803.000000\",\"405622.000000\"");
-        assertTrue(iterator.hasNext());
-        assertEquals(iterator.next(), "8803.000000");
-        assertTrue(iterator.hasNext());
-        assertEquals(iterator.next(), "405622.000000");
-        assertFalse(iterator.hasNext());
-    }
-
-    @Test
-    public void testSendPerfCountersToSensors() {
-        AttributeSensor<String> stringSensor = Sensors.newStringSensor("foo.bar");
-        AttributeSensor<Integer> integerSensor = Sensors.newIntegerSensor("bar.baz");
-        AttributeSensor<Double> doubleSensor = Sensors.newDoubleSensor("baz.quux");
-
-        Collection<WindowsPerformanceCounterPollConfig<?>> polls = ImmutableSet.<WindowsPerformanceCounterPollConfig<?>>of(
-                new WindowsPerformanceCounterPollConfig(stringSensor).performanceCounterName("\\processor information(_total)\\% processor time"),
-                new WindowsPerformanceCounterPollConfig(integerSensor).performanceCounterName("\\integer.sensor"),
-                new WindowsPerformanceCounterPollConfig(doubleSensor).performanceCounterName("\\double\\sensor\\with\\multiple\\sub\\paths")
-        );
-
-        WindowsPerformanceCounterFeed.SendPerfCountersToSensors sendPerfCountersToSensors = new WindowsPerformanceCounterFeed.SendPerfCountersToSensors(entity, polls);
-
-        assertNull(entity.getAttribute(stringSensor));
-
-        StringBuilder responseBuilder = new StringBuilder();
-        // NOTE: This builds the response in a different order to which they are passed to the SendPerfCountersToSensors constructor
-        // this tests that the values are applied correctly even if the (possibly non-deterministic) order in which
-        // they are returned by the Get-Counter scriptlet is different
-        addMockResponse(responseBuilder, "\\\\machine.name\\double\\sensor\\with\\multiple\\sub\\paths", "3.1415926");
-        addMockResponse(responseBuilder, "\\\\win-lge7uj2blau\\processor information(_total)\\% processor time", "99.9");
-        addMockResponse(responseBuilder, "\\\\machine.name\\integer.sensor", "15");
-
-        sendPerfCountersToSensors.onSuccess(new WinRmToolResponse(responseBuilder.toString(), "", 0));
-
-        EntityTestUtils.assertAttributeEquals(entity, stringSensor, "99.9");
-        EntityTestUtils.assertAttributeEquals(entity, integerSensor, 15);
-        EntityTestUtils.assertAttributeEquals(entity, doubleSensor, 3.1415926);
-    }
-
-    private void addMockResponse(StringBuilder responseBuilder, String path, String value) {
-        responseBuilder.append(path);
-        responseBuilder.append(Strings.repeat(" ", 200 - (path.length() + value.length())));
-        responseBuilder.append(value);
-        responseBuilder.append("\r\n");
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/policy/src/main/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetector.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetector.java b/policy/src/main/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetector.java
index 8c8f8f7..c5d7415 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetector.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetector.java
@@ -36,10 +36,10 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
 import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.javalang.AtomicReferences;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/derby/DerbyDatabase.java
----------------------------------------------------------------------
diff --git a/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/derby/DerbyDatabase.java b/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/derby/DerbyDatabase.java
index ffa8bd6..7cd3bd4 100644
--- a/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/derby/DerbyDatabase.java
+++ b/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/derby/DerbyDatabase.java
@@ -36,10 +36,10 @@ import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
+import org.apache.brooklyn.feed.jmx.JmxHelper;
 import org.apache.brooklyn.entity.java.UsesJava;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.core.config.BasicConfigKey;
-import org.apache.brooklyn.sensor.feed.jmx.JmxHelper;
 import org.apache.brooklyn.util.collections.MutableMap;
 
 import com.google.common.base.Objects.ToStringHelper;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/derby/DerbySchema.java
----------------------------------------------------------------------
diff --git a/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/derby/DerbySchema.java b/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/derby/DerbySchema.java
index 23cfb2c..07417a5 100644
--- a/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/derby/DerbySchema.java
+++ b/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/derby/DerbySchema.java
@@ -33,10 +33,10 @@ import org.apache.brooklyn.entity.database.Schema;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.entity.java.UsesJmx;
+import org.apache.brooklyn.feed.jmx.JmxAttributePollConfig;
+import org.apache.brooklyn.feed.jmx.JmxFeed;
+import org.apache.brooklyn.feed.jmx.JmxHelper;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;
-import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
-import org.apache.brooklyn.sensor.feed.jmx.JmxHelper;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/sandbox/extra/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeSaltImpl.java
----------------------------------------------------------------------
diff --git a/sandbox/extra/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeSaltImpl.java b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeSaltImpl.java
index 0070b39..da93a1e 100644
--- a/sandbox/extra/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeSaltImpl.java
+++ b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeSaltImpl.java
@@ -39,10 +39,10 @@ import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.entity.stock.EffectorStartableImpl;
+import org.apache.brooklyn.feed.ssh.SshFeed;
+import org.apache.brooklyn.feed.ssh.SshPollConfig;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.database.postgresql.PostgreSqlNode;
-import org.apache.brooklyn.sensor.feed.ssh.SshFeed;
-import org.apache.brooklyn.sensor.feed.ssh.SshPollConfig;
 import org.apache.brooklyn.util.ssh.BashCommands;
 
 import com.google.common.collect.ImmutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltStackMasterImpl.java
----------------------------------------------------------------------
diff --git a/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltStackMasterImpl.java b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltStackMasterImpl.java
index 8c2a3af..40e38c5 100644
--- a/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltStackMasterImpl.java
+++ b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltStackMasterImpl.java
@@ -20,9 +20,8 @@ package org.apache.brooklyn.entity.salt;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-
+import org.apache.brooklyn.core.feed.ConfigToAttributes;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
-import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
 
 public class SaltStackMasterImpl extends SoftwareProcessImpl implements SaltStackMaster {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixFeed.java
----------------------------------------------------------------------
diff --git a/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixFeed.java b/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixFeed.java
index 587a152..ef26e8c 100644
--- a/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixFeed.java
+++ b/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixFeed.java
@@ -37,13 +37,13 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.EntityFunctions;
+import org.apache.brooklyn.core.feed.AbstractFeed;
+import org.apache.brooklyn.core.feed.AttributePollHandler;
+import org.apache.brooklyn.core.feed.PollHandler;
+import org.apache.brooklyn.core.feed.Poller;
 import org.apache.brooklyn.core.location.SupportsPortForwarding;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
-import org.apache.brooklyn.sensor.feed.AbstractFeed;
-import org.apache.brooklyn.sensor.feed.AttributePollHandler;
-import org.apache.brooklyn.sensor.feed.PollHandler;
-import org.apache.brooklyn.sensor.feed.Poller;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
 import org.apache.brooklyn.util.core.http.HttpTool;
 import org.apache.brooklyn.util.core.http.HttpToolResponse;
 import org.apache.brooklyn.util.net.Cidr;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixPollConfig.java
----------------------------------------------------------------------
diff --git a/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixPollConfig.java b/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixPollConfig.java
index 978261c..388994b 100644
--- a/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixPollConfig.java
+++ b/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixPollConfig.java
@@ -21,9 +21,9 @@ package org.apache.brooklyn.entity.monitoring.zabbix;
 import javax.annotation.Nullable;
 
 import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.sensor.feed.PollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
-import org.apache.brooklyn.sensor.feed.http.JsonFunctions;
+import org.apache.brooklyn.core.feed.PollConfig;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
+import org.apache.brooklyn.feed.http.JsonFunctions;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.core.http.HttpToolResponse;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixServerImpl.java
----------------------------------------------------------------------
diff --git a/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixServerImpl.java b/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixServerImpl.java
index b4f0f6d..9476673 100644
--- a/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixServerImpl.java
+++ b/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixServerImpl.java
@@ -28,10 +28,10 @@ import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.entity.group.AbstractMembershipTrackingPolicy;
 import org.apache.brooklyn.entity.group.DynamicGroup;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeImpl.java
----------------------------------------------------------------------
diff --git a/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeImpl.java b/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeImpl.java
index 6ee1729..d618f0c 100644
--- a/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeImpl.java
+++ b/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeImpl.java
@@ -26,9 +26,9 @@ import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
 import org.apache.brooklyn.util.text.Strings;
 
 import com.google.common.base.Functions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynClusterImpl.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynClusterImpl.java
index 0d66ba3..bbe5bf2 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynClusterImpl.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynClusterImpl.java
@@ -30,9 +30,9 @@ import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceProble
 import org.apache.brooklyn.entity.brooklynnode.effector.BrooklynClusterUpgradeEffectorBody;
 import org.apache.brooklyn.entity.brooklynnode.effector.SelectMasterEffectorBody;
 import org.apache.brooklyn.entity.group.DynamicClusterImpl;
+import org.apache.brooklyn.feed.function.FunctionFeed;
+import org.apache.brooklyn.feed.function.FunctionPollConfig;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
-import org.apache.brooklyn.sensor.feed.function.FunctionFeed;
-import org.apache.brooklyn.sensor.feed.function.FunctionPollConfig;
 import org.apache.brooklyn.util.time.Duration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java
index 91622dd..538c170 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java
@@ -33,8 +33,8 @@ import org.apache.brooklyn.core.entity.EntityDynamicType;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.sensor.Sensors;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
 import org.apache.brooklyn.util.collections.Jsonya;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.config.ConfigBag;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
index c1dd4ed..02f5965 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
@@ -41,6 +41,7 @@ import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceNotUpLogic;
 import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.feed.ConfigToAttributes;
 import org.apache.brooklyn.core.location.Locations;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
@@ -51,15 +52,14 @@ import org.apache.brooklyn.entity.brooklynnode.effector.SetHighAvailabilityPrior
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess.StopSoftwareParameters.StopMode;
 import org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
+import org.apache.brooklyn.feed.http.JsonFunctions;
 import org.apache.http.HttpStatus;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
-import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
-import org.apache.brooklyn.sensor.feed.http.JsonFunctions;
 import org.apache.brooklyn.util.collections.Jsonya;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.config.ConfigBag;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityModeEffectorBody.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityModeEffectorBody.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityModeEffectorBody.java
index ca938e9..17baf37 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityModeEffectorBody.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityModeEffectorBody.java
@@ -26,8 +26,8 @@ import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
 import org.apache.brooklyn.entity.brooklynnode.EntityHttpClient;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNode.SetHighAvailabilityModeEffector;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
-import org.apache.brooklyn.sensor.feed.http.JsonFunctions;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
+import org.apache.brooklyn.feed.http.JsonFunctions;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.http.HttpToolResponse;
 import org.apache.brooklyn.util.guava.Functionals;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefAttributeFeed.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefAttributeFeed.java b/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefAttributeFeed.java
index 42dcc1c..1078d90 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefAttributeFeed.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefAttributeFeed.java
@@ -34,10 +34,10 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.sensor.feed.AbstractFeed;
-import org.apache.brooklyn.sensor.feed.PollHandler;
-import org.apache.brooklyn.sensor.feed.Poller;
-import org.apache.brooklyn.sensor.feed.ssh.SshPollValue;
+import org.apache.brooklyn.core.feed.AbstractFeed;
+import org.apache.brooklyn.core.feed.PollHandler;
+import org.apache.brooklyn.core.feed.Poller;
+import org.apache.brooklyn.feed.ssh.SshPollValue;
 import org.apache.brooklyn.util.core.flags.TypeCoercions;
 import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefAttributePollConfig.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefAttributePollConfig.java b/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefAttributePollConfig.java
index c6e1c6b..badc7e4 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefAttributePollConfig.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefAttributePollConfig.java
@@ -19,7 +19,7 @@
 package org.apache.brooklyn.entity.chef;
 
 import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.sensor.feed.PollConfig;
+import org.apache.brooklyn.core.feed.PollConfig;
 
 import com.google.common.base.Function;
 import com.google.common.base.Functions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/entity/java/JavaAppUtils.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/java/JavaAppUtils.java b/software/base/src/main/java/org/apache/brooklyn/entity/java/JavaAppUtils.java
index c7a743c..9656878 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/java/JavaAppUtils.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/java/JavaAppUtils.java
@@ -32,11 +32,11 @@ import javax.management.openmbean.CompositeData;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.core.config.render.RendererHints;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
+import org.apache.brooklyn.feed.jmx.JmxAttributePollConfig;
+import org.apache.brooklyn.feed.jmx.JmxFeed;
 import org.apache.brooklyn.policy.enricher.RollingTimeWindowMeanEnricher;
 import org.apache.brooklyn.policy.enricher.TimeFractionDeltaEnricher;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
-import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;
-import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
 import org.apache.brooklyn.util.math.MathFunctions;
 import org.apache.brooklyn.util.text.ByteSizeStrings;
 import org.apache.brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java b/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java
index 64ef6ac..ae80754 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java
@@ -30,9 +30,9 @@ import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.effector.AddSensor;
 import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.core.sensor.HttpRequestSensor;
-import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;
-import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
-import org.apache.brooklyn.sensor.feed.jmx.JmxHelper;
+import org.apache.brooklyn.feed.jmx.JmxAttributePollConfig;
+import org.apache.brooklyn.feed.jmx.JmxFeed;
+import org.apache.brooklyn.feed.jmx.JmxHelper;
 import org.apache.brooklyn.sensor.ssh.SshCommandSensor;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.task.DynamicTasks;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxSupport.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxSupport.java b/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxSupport.java
index 62fa577..f633f3c 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxSupport.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxSupport.java
@@ -31,10 +31,10 @@ import org.apache.brooklyn.config.ConfigKey.HasConfigKey;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.location.Locations;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
+import org.apache.brooklyn.feed.jmx.JmxHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.feed.jmx.JmxHelper;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.BrooklynMavenArtifacts;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/entity/java/VanillaJavaAppImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/java/VanillaJavaAppImpl.java b/software/base/src/main/java/org/apache/brooklyn/entity/java/VanillaJavaAppImpl.java
index a81de86..90da4a9 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/java/VanillaJavaAppImpl.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/java/VanillaJavaAppImpl.java
@@ -25,7 +25,7 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
-import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
+import org.apache.brooklyn.feed.jmx.JmxFeed;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineEntityImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineEntityImpl.java b/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineEntityImpl.java
index 72d7bef..58c64fd 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineEntityImpl.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineEntityImpl.java
@@ -28,10 +28,10 @@ import org.apache.brooklyn.core.location.Machines;
 import org.apache.brooklyn.entity.software.base.AbstractSoftwareProcessSshDriver;
 import org.apache.brooklyn.entity.software.base.EmptySoftwareProcessDriver;
 import org.apache.brooklyn.entity.software.base.EmptySoftwareProcessImpl;
+import org.apache.brooklyn.feed.ssh.SshFeed;
+import org.apache.brooklyn.feed.ssh.SshPollConfig;
+import org.apache.brooklyn.feed.ssh.SshPollValue;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.feed.ssh.SshFeed;
-import org.apache.brooklyn.sensor.feed.ssh.SshPollConfig;
-import org.apache.brooklyn.sensor.feed.ssh.SshPollValue;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
 import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.util.exceptions.Exceptions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessSshDriver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessSshDriver.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessSshDriver.java
index a64999c..e381c79 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessSshDriver.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessSshDriver.java
@@ -35,6 +35,7 @@ import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.feed.ConfigToAttributes;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
 import org.apache.brooklyn.entity.software.base.lifecycle.NaiveScriptRunner;
 import org.apache.brooklyn.entity.software.base.lifecycle.ScriptHelper;
@@ -49,7 +50,6 @@ import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
 import org.apache.brooklyn.util.core.internal.ssh.SshTool;
 import org.apache.brooklyn.util.core.internal.ssh.sshj.SshjTool;
 import org.apache.brooklyn.util.core.task.DynamicTasks;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcessImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcessImpl.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcessImpl.java
index f2dc269..b67780b 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcessImpl.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcessImpl.java
@@ -51,12 +51,12 @@ import org.apache.brooklyn.core.entity.lifecycle.Lifecycle.Transition;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceNotUpLogic;
 import org.apache.brooklyn.core.location.LocationConfigKeys;
 import org.apache.brooklyn.core.location.cloud.CloudLocationConfig;
+import org.apache.brooklyn.feed.function.FunctionFeed;
+import org.apache.brooklyn.feed.function.FunctionPollConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
-import org.apache.brooklyn.sensor.feed.function.FunctionFeed;
-import org.apache.brooklyn.sensor.feed.function.FunctionPollConfig;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.config.ConfigBag;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
index 24614af..bd6f477 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
@@ -51,6 +51,7 @@ import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.entity.trait.StartableMethods;
+import org.apache.brooklyn.core.feed.ConfigToAttributes;
 import org.apache.brooklyn.core.location.AbstractLocation;
 import org.apache.brooklyn.core.location.Locations;
 import org.apache.brooklyn.core.location.Machines;
@@ -76,7 +77,6 @@ import com.google.common.collect.Iterables;
 
 import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.task.DynamicTasks;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxAttributePollConfig.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxAttributePollConfig.java b/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxAttributePollConfig.java
new file mode 100644
index 0000000..ae19f45
--- /dev/null
+++ b/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxAttributePollConfig.java
@@ -0,0 +1,74 @@
+/*
+ * 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.feed.jmx;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.feed.PollConfig;
+
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+
+public class JmxAttributePollConfig<T> extends PollConfig<Object, T, JmxAttributePollConfig<T>>{
+
+    private ObjectName objectName;
+    private String attributeName;
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public JmxAttributePollConfig(AttributeSensor<T> sensor) {
+        super(sensor);
+        onSuccess((Function)Functions.identity());
+    }
+
+    public JmxAttributePollConfig(JmxAttributePollConfig<T> other) {
+        super(other);
+        this.objectName = other.objectName;
+        this.attributeName = other.attributeName;
+    }
+
+    public ObjectName getObjectName() {
+        return objectName;
+    }
+    
+    public String getAttributeName() {
+        return attributeName;
+    }
+    
+    public JmxAttributePollConfig<T> objectName(ObjectName val) {
+        this.objectName = val; return this;
+    }
+    
+    public JmxAttributePollConfig<T> objectName(String val) {
+        try {
+            return objectName(new ObjectName(val));
+        } catch (MalformedObjectNameException e) {
+            throw new IllegalArgumentException("Invalid object name ("+val+")", e);
+        }
+    }
+    
+    public JmxAttributePollConfig<T> attributeName(String val) {
+        this.attributeName = val; return this;
+    }
+    
+    @Override protected String toStringBaseName() { return "jmx"; }
+    @Override protected String toStringPollSource() { return objectName+":"+attributeName; }
+
+}


[30/36] incubator-brooklyn git commit: Rename o.a.b.sensor.enricher to o.a.b.core.enricher

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/enricher/stock/CustomAggregatingEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/enricher/stock/CustomAggregatingEnricherTest.java b/core/src/test/java/org/apache/brooklyn/enricher/stock/CustomAggregatingEnricherTest.java
new file mode 100644
index 0000000..dbc84ed
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/enricher/stock/CustomAggregatingEnricherTest.java
@@ -0,0 +1,556 @@
+/*
+ * 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.enricher.stock;
+
+import java.util.Collection;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.location.SimulatedLocation;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.enricher.stock.Enrichers;
+import org.apache.brooklyn.entity.group.BasicGroup;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class CustomAggregatingEnricherTest extends BrooklynAppUnitTestSupport {
+
+    public static final Logger log = LoggerFactory.getLogger(CustomAggregatingEnricherTest.class);
+            
+    private static final long TIMEOUT_MS = 10*1000;
+    private static final long SHORT_WAIT_MS = 50;
+    
+    TestEntity entity;
+    SimulatedLocation loc;
+    
+    AttributeSensor<Integer> intSensor;
+    AttributeSensor<Double> doubleSensor;
+    AttributeSensor<Integer> target;
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        intSensor = new BasicAttributeSensor<Integer>(Integer.class, "int sensor");
+        doubleSensor = new BasicAttributeSensor<Double>(Double.class, "double sensor");
+        target = new BasicAttributeSensor<Integer>(Integer.class, "target sensor");
+        loc = mgmt.getLocationManager().createLocation(LocationSpec.create(SimulatedLocation.class));
+        app.start(ImmutableList.of(loc));
+    }
+    
+    @Test
+    public void testSummingEnricherWithNoProducersDefaultsToNull() {
+        entity.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(target)
+                .computingSum()
+                .fromChildren()
+                .build());
+        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 50), entity, target, null);
+    }
+
+    @Test
+    public void testSummingEnricherWithNoProducers() {
+        entity.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(target)
+                .computingSum()
+                .fromChildren()
+                .defaultValueForUnreportedSensors(11)
+                .valueToReportIfNoSensors(40)
+                .build());
+        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 40);
+    }
+
+    @Test
+    public void testSummingEnricherWhenNoSensorValuesYet() {
+        entity.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(target)
+                .computingSum()
+                .fromHardcodedProducers(ImmutableList.of(entity))
+                .defaultValueForUnreportedSensors(11)
+                .valueToReportIfNoSensors(40)
+                .build());
+        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 11);
+    }
+
+    @Test
+    public void testSummingEnricherWhenNoSensorValuesYetDefaultsToNull() {
+        entity.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(target)
+                .computingSum()
+                .fromHardcodedProducers(ImmutableList.of(entity))
+                .build());
+        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 50), entity, target, null);
+    }
+
+    @Test
+    public void testSummingEnricherWithNoValues() {
+        entity.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(target)
+                .computingSum()
+                .fromHardcodedProducers(ImmutableList.of(entity))
+                .build());
+        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 50), entity, target, null);
+    }
+    
+    @Test
+    public void testSummingEnricherWithOneValue() {
+        entity.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(target)
+                .computingSum()
+                .fromHardcodedProducers(ImmutableList.of(entity))
+                .build());
+
+        entity.setAttribute(intSensor, 1);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 1);
+    }
+    
+    @Test
+    public void testSummingEnricherWhenNullSensorValue() {
+        entity.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(target)
+                .computingSum()
+                .fromHardcodedProducers(ImmutableList.of(entity))
+                .build());
+
+        entity.setAttribute(intSensor, null);
+        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 50), entity, target, null);
+    }
+    
+    @Test
+    public void testSummingEnricherWhenDefaultValueForUnreportedSensors() {
+        entity.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(target)
+                .computingSum()
+                .fromHardcodedProducers(ImmutableList.of(entity))
+                .defaultValueForUnreportedSensors(3)
+                .valueToReportIfNoSensors(5)
+                .build());
+
+        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 3);
+        
+        entity.setAttribute(intSensor, null);
+        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 50), entity, target, 3);
+        
+        entity.setAttribute(intSensor, 1);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 1);
+        
+        entity.setAttribute(intSensor, 7);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 7);
+    }
+    
+    @Test
+    public void testMultipleProducersSum() {
+        TestEntity producer1 = app.createAndManageChild(EntitySpec.create(TestEntity.class)); 
+        TestEntity producer2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        TestEntity producer3 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+
+        entity.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(target)
+                .computingSum()
+                .fromHardcodedProducers(ImmutableList.of(producer1, producer2, producer3))
+                .build());
+
+        producer3.setAttribute(intSensor, 1);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 1);
+
+        producer1.setAttribute(intSensor, 2);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 3);
+
+        producer2.setAttribute(intSensor, 4);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 7);
+    }
+    
+    @Test
+    public void testAveragingEnricherWhenNoAndNullSensorValues() {
+        TestEntity producer1 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        
+        entity.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(doubleSensor)
+                .computingAverage()
+                .fromHardcodedProducers(ImmutableList.of(producer1))
+                .build());
+
+        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 50), entity, doubleSensor, null);
+        
+        producer1.setAttribute(intSensor, null);
+        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 50), entity, doubleSensor, null);
+    }
+
+    @Test
+    public void testAveragingEnricherWhenDefaultValueForUnreportedSensors() {
+        TestEntity producer1 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        
+        entity.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(doubleSensor)
+                .computingAverage()
+                .fromHardcodedProducers(ImmutableList.of(producer1))
+                .defaultValueForUnreportedSensors(3)
+                .valueToReportIfNoSensors(5)
+                .build());
+
+        EntityTestUtils.assertAttributeEqualsEventually(entity, doubleSensor, 3d);
+        
+        producer1.setAttribute(intSensor, null);
+        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 50), entity, doubleSensor, 3d);
+        
+        producer1.setAttribute(intSensor, 4);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, doubleSensor, 4d);
+    }
+
+    @Test
+    public void testAveragingEnricherWhenNoSensors() {
+        entity.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(doubleSensor)
+                .computingAverage()
+                .fromChildren()
+                .defaultValueForUnreportedSensors(3)
+                .valueToReportIfNoSensors(5)
+                .build());
+
+        EntityTestUtils.assertAttributeEqualsEventually(entity, doubleSensor, 5d);
+    }
+
+    @Test
+    public void testAveragingEnricherWhenNoProducersDefaultsToNull() {
+        entity.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(doubleSensor)
+                .computingAverage()
+                .fromChildren()
+                .build());
+
+        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 50), entity, doubleSensor, null);
+    }
+
+    @Test
+    public void testMultipleProducersAverage() {
+        TestEntity producer1 = app.createAndManageChild(EntitySpec.create(TestEntity.class)); 
+        TestEntity producer2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        TestEntity producer3 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        
+        entity.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(doubleSensor)
+                .computingAverage()
+                .fromHardcodedProducers(ImmutableList.of(producer1, producer2, producer3))
+                .build());
+
+        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 50), entity, doubleSensor, null);
+
+        producer1.setAttribute(intSensor, 3);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, doubleSensor, 3d);
+        
+        producer2.setAttribute(intSensor, 1);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, doubleSensor, 2d);
+
+        producer3.setAttribute(intSensor, 5);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, doubleSensor, 3d);
+
+        producer2.setAttribute(intSensor, 4);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, doubleSensor, 4d);
+    }
+    
+    @Test
+    public void testMultipleProducersAverageDefaultingZero() {
+        TestEntity producer1 = app.createAndManageChild(EntitySpec.create(TestEntity.class)); 
+        TestEntity producer2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        TestEntity producer3 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        
+        entity.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(doubleSensor)
+                .computingAverage()
+                .fromHardcodedProducers(ImmutableList.of(producer1, producer2, producer3))
+                .defaultValueForUnreportedSensors(0)
+                .valueToReportIfNoSensors(0)
+                .build());
+
+        EntityTestUtils.assertAttributeEqualsEventually(entity, doubleSensor, 0d);
+
+        producer1.setAttribute(intSensor, 3);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, doubleSensor, 1d);
+
+        producer2.setAttribute(intSensor, 3);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, doubleSensor, 2d);
+
+        producer3.setAttribute(intSensor, 3);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, doubleSensor, 3d);
+    }
+    
+    @Test
+    public void testAggregatesNewMembersOfGroup() {
+        BasicGroup group = app.createAndManageChild(EntitySpec.create(BasicGroup.class));
+        TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        TestEntity p2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        log.debug("created {} and the entities it will contain {} {}", new Object[] {group, p1, p2});
+
+        group.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(target)
+                .computingSum()
+                .fromMembers()
+                .defaultValueForUnreportedSensors(0)
+                .valueToReportIfNoSensors(0)
+                .build());
+
+        EntityTestUtils.assertAttributeEqualsEventually(group, target, 0);
+
+        group.addMember(p1);
+        p1.setAttribute(intSensor, 1);
+        EntityTestUtils.assertAttributeEqualsEventually(group, target, 1);
+
+        group.addMember(p2);
+        p2.setAttribute(intSensor, 2);
+        EntityTestUtils.assertAttributeEqualsEventually(group, target, 3);
+
+        group.removeMember(p2);
+        EntityTestUtils.assertAttributeEqualsEventually(group, target, 1);
+    }
+    
+    @Test(groups = "Integration", invocationCount=50)
+    public void testAggregatesGroupMembersFiftyTimes() {
+        testAggregatesNewMembersOfGroup();
+    }
+    
+    @Test
+    public void testAggregatesExistingMembersOfGroup() {
+        BasicGroup group = app.addChild(EntitySpec.create(BasicGroup.class));
+        TestEntity p1 = app.getManagementContext().getEntityManager().createEntity(EntitySpec.create(TestEntity.class).parent(group)); 
+        TestEntity p2 = app.getManagementContext().getEntityManager().createEntity(EntitySpec.create(TestEntity.class).parent(group)); 
+        group.addMember(p1);
+        group.addMember(p2);
+        p1.setAttribute(intSensor, 1);
+        Entities.manage(group);
+        
+        group.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(target)
+                .computingSum()
+                .fromMembers()
+                .build());
+
+
+        EntityTestUtils.assertAttributeEqualsEventually(group, target, 1);
+
+        p2.setAttribute(intSensor, 2);
+        EntityTestUtils.assertAttributeEqualsEventually(group, target, 3);
+        
+        group.removeMember(p2);
+        EntityTestUtils.assertAttributeEqualsEventually(group, target, 1);
+    }
+    
+    @Test
+    public void testAggregatesMembersOfProducer() {
+        BasicGroup group = app.addChild(EntitySpec.create(BasicGroup.class));
+        TestEntity p1 = app.getManagementContext().getEntityManager().createEntity(EntitySpec.create(TestEntity.class).parent(group)); 
+        TestEntity p2 = app.getManagementContext().getEntityManager().createEntity(EntitySpec.create(TestEntity.class).parent(group)); 
+        group.addMember(p1);
+        group.addMember(p2);
+        p1.setAttribute(intSensor, 1);
+        Entities.manage(group);
+        
+        app.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(target)
+                .computingSum()
+                .from(group)
+                .fromMembers()
+                .build());
+
+
+        EntityTestUtils.assertAttributeEqualsEventually(app, target, 1);
+
+        p2.setAttribute(intSensor, 2);
+        EntityTestUtils.assertAttributeEqualsEventually(app, target, 3);
+        
+        group.removeMember(p2);
+        EntityTestUtils.assertAttributeEqualsEventually(app, target, 1);
+    }
+    
+    @Test
+    public void testAppliesFilterWhenAggregatingMembersOfGroup() {
+        BasicGroup group = app.createAndManageChild(EntitySpec.create(BasicGroup.class));
+        TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        TestEntity p2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        TestEntity p3 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        group.addMember(p1);
+        group.addMember(p2);
+        p1.setAttribute(intSensor, 1);
+        p2.setAttribute(intSensor, 2);
+        p3.setAttribute(intSensor, 4);
+        
+        group.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(target)
+                .computingSum()
+                .fromMembers()
+                .entityFilter(Predicates.equalTo((Entity)p1))
+                .build());
+
+        EntityTestUtils.assertAttributeEqualsEventually(group, target, 1);
+        
+        group.addMember(p3);
+        EntityTestUtils.assertAttributeEqualsContinually(ImmutableMap.of("timeout", SHORT_WAIT_MS), group, target, 1);
+    }
+    
+    @Test
+    public void testAggregatesNewChidren() {
+        entity.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(target)
+                .computingSum()
+                .fromChildren()
+                .defaultValueForUnreportedSensors(0)
+                .valueToReportIfNoSensors(0)
+                .build());
+
+        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 0);
+
+        TestEntity p1 = entity.createAndManageChild(EntitySpec.create(TestEntity.class));
+        p1.setAttribute(intSensor, 1);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 1);
+
+        TestEntity p2 = entity.createAndManageChild(EntitySpec.create(TestEntity.class));
+        p2.setAttribute(intSensor, 2);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 3);
+
+        Entities.unmanage(p2);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 1);
+    }
+    
+    @Test
+    public void testAggregatesExistingChildren() {
+        TestEntity p1 = entity.createAndManageChild(EntitySpec.create(TestEntity.class));
+        TestEntity p2 = entity.createAndManageChild(EntitySpec.create(TestEntity.class));
+        p1.setAttribute(intSensor, 1);
+        
+        entity.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(target)
+                .computingSum()
+                .fromChildren()
+                .build());
+
+
+        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 1);
+
+        p2.setAttribute(intSensor, 2);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 3);
+        
+        Entities.unmanage(p2);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 1);
+    }
+    
+    @Test
+    public void testAggregatesChildrenOfProducer() {
+        TestEntity p1 = entity.createAndManageChild(EntitySpec.create(TestEntity.class));
+        TestEntity p2 = entity.createAndManageChild(EntitySpec.create(TestEntity.class));
+        p1.setAttribute(intSensor, 1);
+        
+        app.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(target)
+                .computingSum()
+                .from(entity)
+                .fromChildren()
+                .build());
+
+
+        EntityTestUtils.assertAttributeEqualsEventually(app, target, 1);
+
+        p2.setAttribute(intSensor, 2);
+        EntityTestUtils.assertAttributeEqualsEventually(app, target, 3);
+        
+        Entities.unmanage(p2);
+        EntityTestUtils.assertAttributeEqualsEventually(app, target, 1);
+    }
+    
+    @Test
+    public void testAppliesFilterWhenAggregatingChildrenOfGroup() {
+        TestEntity p1 = entity.createAndManageChild(EntitySpec.create(TestEntity.class));
+        p1.setAttribute(intSensor, 1);
+        
+        entity.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(target)
+                .computingSum()
+                .fromChildren()
+                .entityFilter(Predicates.equalTo((Entity)p1))
+                .build());
+
+        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 1);
+        
+        TestEntity p2 = entity.createAndManageChild(EntitySpec.create(TestEntity.class));
+        p2.setAttribute(intSensor, 2);
+        EntityTestUtils.assertAttributeEqualsContinually(ImmutableMap.of("timeout", SHORT_WAIT_MS), entity, target, 1);
+    }
+    
+    @Test
+    public void testCustomAggregatingFunction() {
+        TestEntity producer1 = app.createAndManageChild(EntitySpec.create(TestEntity.class)); 
+        Function<Collection<Integer>,Integer> aggregator = new Function<Collection<Integer>, Integer>() {
+            public Integer apply(Collection<Integer> input) { 
+                int result = 1;
+                for (Integer in : input) result += in*in;
+                return result;
+            }
+        };
+        
+        entity.addEnricher(Enrichers.builder()
+                .aggregating(intSensor)
+                .publishing(target)
+                .computing(aggregator)
+                .fromHardcodedProducers(ImmutableList.of(producer1))
+                .defaultValueForUnreportedSensors(0)
+                .build());
+
+        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 1);
+        
+        // Event by producer
+        producer1.setAttribute(intSensor, 2);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 5);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/enricher/stock/EnrichersTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/enricher/stock/EnrichersTest.java b/core/src/test/java/org/apache/brooklyn/enricher/stock/EnrichersTest.java
new file mode 100644
index 0000000..e5c48fa
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/enricher/stock/EnrichersTest.java
@@ -0,0 +1,501 @@
+/*
+ * 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.enricher.stock;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.Enricher;
+import org.apache.brooklyn.api.sensor.SensorEvent;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.EntityAdjuncts;
+import org.apache.brooklyn.core.entity.RecordingSensorEventListener;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.enricher.stock.Enrichers;
+import org.apache.brooklyn.entity.group.BasicGroup;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.util.collections.CollectionFunctionals;
+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.guava.Functionals;
+import org.apache.brooklyn.util.text.StringFunctions;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+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;
+import com.google.common.collect.Iterables;
+import com.google.common.reflect.TypeToken;
+
+@SuppressWarnings("serial")
+public class EnrichersTest extends BrooklynAppUnitTestSupport {
+
+    public static final AttributeSensor<Integer> NUM1 = Sensors.newIntegerSensor("test.num1");
+    public static final AttributeSensor<Integer> NUM2 = Sensors.newIntegerSensor("test.num2");
+    public static final AttributeSensor<Integer> NUM3 = Sensors.newIntegerSensor("test.num3");
+    public static final AttributeSensor<String> STR1 = Sensors.newStringSensor("test.str1");
+    public static final AttributeSensor<String> STR2 = Sensors.newStringSensor("test.str2");
+    public static final AttributeSensor<Set<Object>> SET1 = Sensors.newSensor(new TypeToken<Set<Object>>() {}, "test.set1", "set1 descr");
+    public static final AttributeSensor<Long> LONG1 = Sensors.newLongSensor("test.long1");
+    public static final AttributeSensor<Map<String,String>> MAP1 = Sensors.newSensor(new TypeToken<Map<String,String>>() {}, "test.map1", "map1 descr");
+    @SuppressWarnings("rawtypes")
+    public static final AttributeSensor<Map> MAP2 = Sensors.newSensor(Map.class, "test.map2");
+    
+    private TestEntity entity;
+    private TestEntity entity2;
+    private BasicGroup group;
+    
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        entity2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        group = app.createAndManageChild(EntitySpec.create(BasicGroup.class));
+    }
+    
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testAdding() {
+        Enricher enr = entity.addEnricher(Enrichers.builder()
+                .combining(NUM1, NUM2)
+                .publishing(NUM3)
+                .computingSum()
+                .build());
+        
+        Assert.assertEquals(EntityAdjuncts.getNonSystemEnrichers(entity), ImmutableList.of(enr));
+        
+        entity.setAttribute(NUM1, 2);
+        entity.setAttribute(NUM2, 3);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, NUM3, 5);
+    }
+    
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testCombiningWithCustomFunction() {
+        entity.addEnricher(Enrichers.builder()
+                .combining(NUM1, NUM2)
+                .publishing(NUM3)
+                .computing(Functions.constant(1))
+                .build());
+        
+        entity.setAttribute(NUM1, 2);
+        entity.setAttribute(NUM2, 3);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, NUM3, 1);
+    }
+    
+    @SuppressWarnings("unchecked")
+    @Test(groups="Integration") // because takes a second
+    public void testCombiningRespectsUnchanged() {
+        entity.addEnricher(Enrichers.builder()
+                .combining(NUM1, NUM2)
+                .<Object>publishing(NUM3)
+                .computing(new Function<Iterable<Integer>, Object>() {
+                        @Override public Object apply(Iterable<Integer> input) {
+                            if (input != null && Iterables.contains(input, 123)) {
+                                return Enrichers.sum(input, 0, 0, new TypeToken<Integer>(){});
+                            } else {
+                                return Entities.UNCHANGED;
+                            }
+                        }})
+                .build());
+        
+        entity.setAttribute(NUM1, 123);
+        entity.setAttribute(NUM2, 3);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, NUM3, 126);
+        
+        entity.setAttribute(NUM1, 2);
+        EntityTestUtils.assertAttributeEqualsContinually(entity, NUM3, 126);
+    }
+    
+    @Test
+    public void testFromEntity() {
+        entity.addEnricher(Enrichers.builder()
+                .transforming(NUM1)
+                .publishing(NUM1)
+                .computing(Functions.<Integer>identity())
+                .from(entity2)
+                .build());
+        
+        entity2.setAttribute(NUM1, 2);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, NUM1, 2);
+    }
+    
+    @Test
+    public void testTransforming() {
+        entity.addEnricher(Enrichers.builder()
+                .transforming(STR1)
+                .publishing(STR2)
+                .computing(StringFunctions.append("mysuffix"))
+                .build());
+        
+        entity.setAttribute(STR1, "myval");
+        EntityTestUtils.assertAttributeEqualsEventually(entity, STR2, "myvalmysuffix");
+    }
+
+    @Test
+    public void testTransformingCastsResult() {
+        entity.addEnricher(Enrichers.builder()
+                .transforming(NUM1)
+                .publishing(LONG1)
+                .computing(Functions.constant(Long.valueOf(1)))
+                .build());
+        
+        entity.setAttribute(NUM1, 123);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, LONG1, Long.valueOf(1));
+    }
+
+    @Test
+    public void testTransformingFromEvent() {
+        entity.addEnricher(Enrichers.builder()
+                .transforming(STR1)
+                .publishing(STR2)
+                .computingFromEvent(new Function<SensorEvent<String>, String>() {
+                    @Override public String apply(SensorEvent<String> input) {
+                        return input.getValue() + "mysuffix";
+                    }})
+                .build());
+        
+        entity.setAttribute(STR1, "myval");
+        EntityTestUtils.assertAttributeEqualsEventually(entity, STR2, "myvalmysuffix");
+    }
+
+    @Test(groups="Integration") // because takes a second
+    public void testTransformingRespectsUnchangedButWillRepublish() {
+        RecordingSensorEventListener<String> record = new RecordingSensorEventListener<>();
+        app.getManagementContext().getSubscriptionManager().subscribe(entity, STR2, record);
+        
+        entity.addEnricher(Enrichers.builder()
+                .transforming(STR1)
+                .<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.getEvents(), CollectionFunctionals.sizeEquals(0));
+
+        entity.setAttribute(STR1, "myval");
+        Asserts.eventually(Suppliers.ofInstance(record), 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), 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), CollectionFunctionals.sizeEquals(5));
+    }
+
+    public void testTransformingSuppressDuplicates() {
+        RecordingSensorEventListener<String> 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), 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.getEvents(), CollectionFunctionals.sizeEquals(3));
+    }
+
+    @Test
+    public void testPropagating() {
+        entity.addEnricher(Enrichers.builder()
+                .propagating(ImmutableList.of(STR1))
+                .from(entity2)
+                .build());
+        
+        entity2.setAttribute(STR1, "myval");
+        EntityTestUtils.assertAttributeEqualsEventually(entity, STR1, "myval");
+        
+        entity2.setAttribute(STR1, null);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, STR1, null);
+    }
+    
+    @Test
+    public void testPropagatingAndRenaming() {
+        entity.addEnricher(Enrichers.builder()
+                .propagating(ImmutableMap.of(STR1, STR2))
+                .from(entity2)
+                .build());
+        
+        entity2.setAttribute(STR1, "myval");
+        EntityTestUtils.assertAttributeEqualsEventually(entity, STR2, "myval");
+    }
+    
+    // FIXME What is default? members? children? fail?
+    @Test
+    public void testAggregatingGroupSum() {
+        TestEntity child1 = group.addChild(EntitySpec.create(TestEntity.class));
+        Entities.manage(child1);
+        group.addMember(entity);
+        group.addMember(entity2);
+        group.addEnricher(Enrichers.builder()
+                .aggregating(NUM1)
+                .publishing(NUM2)
+                .fromMembers()
+                .computingSum()
+                .build());
+        
+        child1.setAttribute(NUM1, 1);
+        entity.setAttribute(NUM1, 2);
+        entity2.setAttribute(NUM1, 3);
+        EntityTestUtils.assertAttributeEqualsEventually(group, NUM2, 5);
+    }
+    
+    @Test
+    public void testAggregatingChildrenSum() {
+        group.addMember(entity);
+        TestEntity child1 = group.addChild(EntitySpec.create(TestEntity.class));
+        Entities.manage(child1);
+        TestEntity child2 = group.addChild(EntitySpec.create(TestEntity.class));
+        Entities.manage(child2);
+        group.addEnricher(Enrichers.builder()
+                .aggregating(NUM1)
+                .publishing(NUM2)
+                .fromChildren()
+                .computingSum()
+                .build());
+        
+        entity.setAttribute(NUM1, 1);
+        child1.setAttribute(NUM1, 2);
+        child2.setAttribute(NUM1, 3);
+        EntityTestUtils.assertAttributeEqualsEventually(group, NUM2, 5);
+    }
+
+    @Test
+    public void testAggregatingExcludingBlankString() {
+        group.addMember(entity);
+        group.addMember(entity2);
+        group.addEnricher(Enrichers.builder()
+                .aggregating(STR1)
+                .publishing(SET1)
+                .fromMembers()
+                .excludingBlank()
+                .computing(new Function<Collection<?>, Set<Object>>() {
+                    @Override public Set<Object> apply(Collection<?> input) {
+                        // accept null values, so don't use ImmutableSet
+                        return (input == null) ? ImmutableSet.<Object>of() : MutableSet.<Object>copyOf(input);
+                    }})
+                .build());
+        
+        entity.setAttribute(STR1, "1");
+        entity2.setAttribute(STR1, "2");
+        EntityTestUtils.assertAttributeEqualsEventually(group, SET1, ImmutableSet.<Object>of("1", "2"));
+        
+        entity.setAttribute(STR1, "3");
+        entity2.setAttribute(STR1, null);
+        EntityTestUtils.assertAttributeEqualsEventually(group, SET1, ImmutableSet.<Object>of("3"));
+        
+        entity.setAttribute(STR1, "");
+        entity2.setAttribute(STR1, "4");
+        EntityTestUtils.assertAttributeEqualsEventually(group, SET1, ImmutableSet.<Object>of("4"));
+    }
+
+    @Test
+    public void testAggregatingExcludingNull() {
+        group.addMember(entity);
+        group.addEnricher(Enrichers.builder()
+                .aggregating(NUM1)
+                .publishing(SET1)
+                .fromMembers()
+                .excludingBlank()
+                .computing(new Function<Collection<?>, Set<Object>>() {
+                    @Override public Set<Object> apply(Collection<?> input) {
+                        // accept null values, so don't use ImmutableSet
+                        return (input == null) ? ImmutableSet.<Object>of() : MutableSet.<Object>copyOf(input);
+                    }})
+                .build());
+
+        EntityTestUtils.assertAttributeEqualsEventually(group, SET1, ImmutableSet.<Object>of());
+
+        entity.setAttribute(NUM1, 1);
+        EntityTestUtils.assertAttributeEqualsEventually(group, SET1, ImmutableSet.<Object>of(1));
+        
+        entity.setAttribute(NUM1, null);
+        EntityTestUtils.assertAttributeEqualsEventually(group, SET1, ImmutableSet.<Object>of());
+        
+        entity.setAttribute(NUM1, 2);
+        EntityTestUtils.assertAttributeEqualsEventually(group, SET1, ImmutableSet.<Object>of(2));
+    }
+
+    @Test
+    public void testAggregatingCastsResult() {
+        group.addMember(entity);
+        group.addEnricher(Enrichers.builder()
+                .aggregating(NUM1)
+                .publishing(LONG1)
+                .fromMembers()
+                .computing(Functions.constant(Long.valueOf(1)))
+                .build());
+        
+        entity.setAttribute(NUM1, 123);
+        EntityTestUtils.assertAttributeEqualsEventually(group, LONG1, Long.valueOf(1));
+    }
+    
+    @Test(groups="Integration") // because takes a second
+    public void testAggregatingRespectsUnchanged() {
+        group.addMember(entity);
+        group.addEnricher(Enrichers.builder()
+                .aggregating(NUM1)
+                .<Object>publishing(LONG1)
+                .fromMembers()
+                .computing(new Function<Iterable<Integer>, Object>() {
+                        @Override public Object apply(Iterable<Integer> input) {
+                            if (input != null && Iterables.contains(input, 123)) {
+                                return Enrichers.sum(input, 0, 0, new TypeToken<Integer>(){});
+                            } else {
+                                return Entities.UNCHANGED;
+                            }
+                        }})
+                .build());
+        
+        entity.setAttribute(NUM1, 123);
+        EntityTestUtils.assertAttributeEqualsEventually(group, LONG1, Long.valueOf(123));
+        
+        entity.setAttribute(NUM1, 987654);
+        EntityTestUtils.assertAttributeEqualsContinually(group, LONG1, Long.valueOf(123));
+    }
+    @Test
+    public void testUpdatingMap1() {
+        entity.addEnricher(Enrichers.builder()
+                .updatingMap(MAP1)
+                .from(LONG1)
+                .computing(Functionals.ifEquals(-1L).value("-1 is not allowed"))
+                .build());
+        
+        doUpdatingMapChecks(MAP1);
+    }
+    
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Test
+    public void testUpdatingMap2() {
+        entity.addEnricher(Enrichers.builder()
+                .updatingMap((AttributeSensor)MAP2)
+                .from(LONG1)
+                .computing(Functionals.ifEquals(-1L).value("-1 is not allowed"))
+                .build());
+        
+        doUpdatingMapChecks(MAP2);
+    }
+    
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    protected void doUpdatingMapChecks(AttributeSensor mapSensor) {
+        EntityTestUtils.assertAttributeEqualsEventually(entity, mapSensor, MutableMap.<String,String>of());
+        
+        entity.setAttribute(LONG1, -1L);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, mapSensor, MutableMap.<String,String>of(
+            LONG1.getName(), "-1 is not allowed"));
+        
+        entity.setAttribute(LONG1, 1L);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, mapSensor, MutableMap.<String,String>of());
+    }
+
+    private static AttributeSensor<Object> LIST_SENSOR = Sensors.newSensor(Object.class, "sensor.list");
+    
+    @Test
+    public void testJoinerDefault() {
+        entity.addEnricher(Enrichers.builder()
+                .joining(LIST_SENSOR)
+                .publishing(TestEntity.NAME)
+                .build());
+        // null values ignored, and it quotes
+        entity.setAttribute(LIST_SENSOR, MutableList.<String>of("a", "\"b").append(null));
+        EntityTestUtils.assertAttributeEqualsEventually(entity, TestEntity.NAME, "\"a\",\"\\\"b\"");
+        
+        // empty list causes ""
+        entity.setAttribute(LIST_SENSOR, MutableList.<String>of().append(null));
+        EntityTestUtils.assertAttributeEqualsEventually(entity, TestEntity.NAME, "");
+        
+        // null causes null
+        entity.setAttribute(LIST_SENSOR, null);
+        EntityTestUtils.assertAttributeEqualsEventually(entity, TestEntity.NAME, null);
+    }
+
+    @Test
+    public void testJoinerUnquoted() {
+        entity.setAttribute(LIST_SENSOR, MutableList.<String>of("a", "\"b", "ccc").append(null));
+        entity.addEnricher(Enrichers.builder()
+            .joining(LIST_SENSOR)
+            .publishing(TestEntity.NAME)
+            .minimum(1)
+            .maximum(2)
+            .separator(":")
+            .quote(false)
+            .build());
+        // in this case, it should be immediately available upon adding the enricher
+        EntityTestUtils.assertAttributeEquals(entity, TestEntity.NAME, "a:\"b");
+        
+        // empty list causes null here, because below the minimum
+        entity.setAttribute(LIST_SENSOR, MutableList.<String>of().append(null));
+        EntityTestUtils.assertAttributeEqualsEventually(entity, TestEntity.NAME, null);
+    }
+
+    @Test
+    public void testJoinerMinMax() {
+        entity.addEnricher(Enrichers.builder()
+                .joining(LIST_SENSOR)
+                .publishing(TestEntity.NAME)
+                .minimum(2)
+                .maximum(4)
+                .quote(false)
+                .build());
+        // null values ignored, and it quotes
+        entity.setAttribute(LIST_SENSOR, MutableList.<String>of("a", "b"));
+        EntityTestUtils.assertAttributeEqualsEventually(entity, TestEntity.NAME, "a,b");
+        
+        // empty list causes ""
+        entity.setAttribute(LIST_SENSOR, MutableList.<String>of("x"));
+        EntityTestUtils.assertAttributeEqualsEventually(entity, TestEntity.NAME, null);
+        
+        // null causes null
+        entity.setAttribute(LIST_SENSOR, MutableList.<String>of("a", "b", "c", "d", "e"));
+        EntityTestUtils.assertAttributeEqualsEventually(entity, TestEntity.NAME, "a,b,c,d");
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/enricher/stock/SensorPropagatingEnricherDeprecatedTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/enricher/stock/SensorPropagatingEnricherDeprecatedTest.java b/core/src/test/java/org/apache/brooklyn/enricher/stock/SensorPropagatingEnricherDeprecatedTest.java
new file mode 100644
index 0000000..a52e2ee
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/enricher/stock/SensorPropagatingEnricherDeprecatedTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.enricher.stock;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.SensorEvent;
+import org.apache.brooklyn.api.sensor.SensorEventListener;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.enricher.stock.SensorPropagatingEnricher;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.javalang.AtomicReferences;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableMap;
+
+public class SensorPropagatingEnricherDeprecatedTest extends BrooklynAppUnitTestSupport {
+
+    private TestEntity entity;
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+    }
+    
+    @Test
+    public void testPropagatesSpecificSensor() {
+        app.addEnricher(SensorPropagatingEnricher.newInstanceListeningTo(entity, TestEntity.NAME));
+
+        // name propagated
+        entity.setAttribute(TestEntity.NAME, "foo");
+        EntityTestUtils.assertAttributeEqualsEventually(app, TestEntity.NAME, "foo");
+        
+        // sequence not propagated
+        entity.setAttribute(TestEntity.SEQUENCE, 2);
+        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 100), app, TestEntity.SEQUENCE, null);
+    }
+    
+    @Test
+    public void testPropagatesAllSensors() {
+        app.addEnricher(SensorPropagatingEnricher.newInstanceListeningToAllSensors(entity));
+
+        // all attributes propagated
+        entity.setAttribute(TestEntity.NAME, "foo");
+        entity.setAttribute(TestEntity.SEQUENCE, 2);
+        
+        EntityTestUtils.assertAttributeEqualsEventually(app, TestEntity.NAME, "foo");
+        EntityTestUtils.assertAttributeEqualsEventually(app, TestEntity.SEQUENCE, 2);
+        
+        // notification-sensor propagated
+        final AtomicReference<Integer> notif = new AtomicReference<Integer>();
+        app.subscribe(app, TestEntity.MY_NOTIF, new SensorEventListener<Integer>() {
+                @Override public void onEvent(SensorEvent<Integer> event) {
+                    notif.set(event.getValue());
+                }});
+        entity.emit(TestEntity.MY_NOTIF, 7);
+        Asserts.eventually(AtomicReferences.supplier(notif), Predicates.equalTo(7));
+    }
+    
+    @Test
+    public void testPropagatesAllBut() {
+        app.addEnricher(SensorPropagatingEnricher.newInstanceListeningToAllSensorsBut(entity, TestEntity.SEQUENCE)) ;
+
+        // name propagated
+        entity.setAttribute(TestEntity.NAME, "foo");
+        EntityTestUtils.assertAttributeEqualsEventually(app, TestEntity.NAME, "foo");
+        
+        // sequence not propagated
+        entity.setAttribute(TestEntity.SEQUENCE, 2);
+        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 100), app, TestEntity.SEQUENCE, null);
+    }
+    
+    @Test
+    public void testPropagatingAsDifferentSensor() {
+        final AttributeSensor<String> ANOTHER_ATTRIBUTE = Sensors.newStringSensor("another.attribute", "");
+        app.addEnricher(SensorPropagatingEnricher.newInstanceRenaming(entity, ImmutableMap.of(TestEntity.NAME, ANOTHER_ATTRIBUTE)));
+
+        // name propagated as different attribute
+        entity.setAttribute(TestEntity.NAME, "foo");
+        EntityTestUtils.assertAttributeEqualsEventually(app, ANOTHER_ATTRIBUTE, "foo");
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/enricher/stock/SensorPropagatingEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/enricher/stock/SensorPropagatingEnricherTest.java b/core/src/test/java/org/apache/brooklyn/enricher/stock/SensorPropagatingEnricherTest.java
new file mode 100644
index 0000000..c660df1
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/enricher/stock/SensorPropagatingEnricherTest.java
@@ -0,0 +1,218 @@
+/*
+ * 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.enricher.stock;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.EnricherSpec;
+import org.apache.brooklyn.api.sensor.SensorEvent;
+import org.apache.brooklyn.api.sensor.SensorEventListener;
+import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.enricher.stock.Enrichers;
+import org.apache.brooklyn.enricher.stock.Propagator;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.javalang.AtomicReferences;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class SensorPropagatingEnricherTest extends BrooklynAppUnitTestSupport {
+
+    private TestEntity entity;
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+    }
+    
+    @Test
+    public void testPropagatesSpecificSensor() {
+        app.addEnricher(Enrichers.builder()
+                .propagating(TestEntity.NAME)
+                .from(entity)
+                .build());
+
+        // name propagated
+        entity.setAttribute(TestEntity.NAME, "foo");
+        EntityTestUtils.assertAttributeEqualsEventually(app, TestEntity.NAME, "foo");
+        
+        // sequence not propagated
+        entity.setAttribute(TestEntity.SEQUENCE, 2);
+        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 100), app, TestEntity.SEQUENCE, null);
+    }
+    
+    @Test
+    public void testPropagatesCurrentValue() {
+        entity.setAttribute(TestEntity.NAME, "foo");
+        
+        app.addEnricher(Enrichers.builder()
+                .propagating(TestEntity.NAME)
+                .from(entity)
+                .build());
+
+        // name propagated
+        EntityTestUtils.assertAttributeEqualsEventually(app, TestEntity.NAME, "foo");
+    }
+    
+    @Test
+    public void testPropagatesAllStaticSensors() {
+        app.addEnricher(Enrichers.builder()
+                .propagatingAll()
+                .from(entity)
+                .build());
+
+        // all attributes propagated
+        entity.setAttribute(TestEntity.NAME, "foo");
+        entity.setAttribute(TestEntity.SEQUENCE, 2);
+        
+        EntityTestUtils.assertAttributeEqualsEventually(app, TestEntity.NAME, "foo");
+        EntityTestUtils.assertAttributeEqualsEventually(app, TestEntity.SEQUENCE, 2);
+        
+        // notification-sensor propagated
+        final AtomicReference<Integer> notif = new AtomicReference<Integer>();
+        app.subscribe(app, TestEntity.MY_NOTIF, new SensorEventListener<Integer>() {
+                @Override public void onEvent(SensorEvent<Integer> event) {
+                    notif.set(event.getValue());
+                }});
+        entity.emit(TestEntity.MY_NOTIF, 7);
+        Asserts.eventually(AtomicReferences.supplier(notif), Predicates.equalTo(7));
+    }
+    
+    @Test
+    public void testPropagatesAllSensorsIncludesDynamicallyAdded() {
+        AttributeSensor<String> dynamicAttribute = Sensors.newStringSensor("test.dynamicsensor.strattrib");
+        BasicNotificationSensor<String> dynamicNotificationSensor = new BasicNotificationSensor(String.class, "test.dynamicsensor.strnotif");
+        
+        app.addEnricher(Enrichers.builder()
+                .propagatingAll()
+                .from(entity)
+                .build());
+
+        entity.setAttribute(dynamicAttribute, "foo");
+        
+        EntityTestUtils.assertAttributeEqualsEventually(app, dynamicAttribute, "foo");
+        
+        // notification-sensor propagated
+        final AtomicReference<String> notif = new AtomicReference<String>();
+        app.subscribe(app, dynamicNotificationSensor, new SensorEventListener<String>() {
+                @Override public void onEvent(SensorEvent<String> event) {
+                    notif.set(event.getValue());
+                }});
+        entity.emit(dynamicNotificationSensor, "mynotifval");
+        Asserts.eventually(AtomicReferences.supplier(notif), Predicates.equalTo("mynotifval"));
+    }
+    
+    @Test
+    public void testPropagatesAllBut() {
+        app.addEnricher(Enrichers.builder()
+                .propagatingAllBut(TestEntity.SEQUENCE)
+                .from(entity)
+                .build());
+
+        // name propagated
+        entity.setAttribute(TestEntity.NAME, "foo");
+        EntityTestUtils.assertAttributeEqualsEventually(app, TestEntity.NAME, "foo");
+        
+        // sequence not propagated
+        entity.setAttribute(TestEntity.SEQUENCE, 2);
+        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 100), app, TestEntity.SEQUENCE, null);
+    }
+    
+    @Test
+    public void testPropagatingAsDifferentSensor() {
+        final AttributeSensor<String> ANOTHER_ATTRIBUTE = Sensors.newStringSensor("another.attribute", "");
+        
+        app.addEnricher(Enrichers.builder()
+                .propagating(ImmutableMap.of(TestEntity.NAME, ANOTHER_ATTRIBUTE))
+                .from(entity)
+                .build());
+
+        // name propagated as different attribute
+        entity.setAttribute(TestEntity.NAME, "foo");
+        EntityTestUtils.assertAttributeEqualsEventually(app, ANOTHER_ATTRIBUTE, "foo");
+    }
+    
+    @Test
+    public void testEnricherSpecPropagatesSpecificSensor() throws Exception {
+        app.addEnricher(EnricherSpec.create(Propagator.class)
+                .configure(MutableMap.builder()
+                        .putIfNotNull(Propagator.PRODUCER, entity)
+                        .putIfNotNull(Propagator.PROPAGATING, ImmutableList.of(TestEntity.NAME))
+                        .build()));
+
+        // name propagated
+        entity.setAttribute(TestEntity.NAME, "foo");
+        EntityTestUtils.assertAttributeEqualsEventually(app, TestEntity.NAME, "foo");
+        
+        // sequence not propagated
+        entity.setAttribute(TestEntity.SEQUENCE, 2);
+        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 100), app, TestEntity.SEQUENCE, null);
+    }
+    
+    @Test
+    public void testEnricherSpecPropagatesSpecificSensorAndMapsOthers() throws Exception {
+        final AttributeSensor<String> ANOTHER_ATTRIBUTE = Sensors.newStringSensor("another.attribute", "");
+        
+        app.addEnricher(EnricherSpec.create(Propagator.class)
+                .configure(MutableMap.builder()
+                        .putIfNotNull(Propagator.PRODUCER, entity)
+                        .putIfNotNull(Propagator.SENSOR_MAPPING, ImmutableMap.of(TestEntity.NAME, ANOTHER_ATTRIBUTE))
+                        .putIfNotNull(Propagator.PROPAGATING, ImmutableList.of(TestEntity.SEQUENCE))
+                        .build()));
+
+        // name propagated as alternative sensor
+        entity.setAttribute(TestEntity.NAME, "foo");
+        EntityTestUtils.assertAttributeEqualsEventually(app, ANOTHER_ATTRIBUTE, "foo");
+        
+        // sequence also propagated
+        entity.setAttribute(TestEntity.SEQUENCE, 2);
+        EntityTestUtils.assertAttributeEqualsEventually(app, TestEntity.SEQUENCE, 2);
+
+        // name not propagated as original sensor
+        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 100), app, TestEntity.NAME, null);
+    }
+    
+    @Test
+    public void testEnricherSpecThrowsOnPropagatesAndPropagatesAllSet() throws Exception {
+        try {
+            app.addEnricher(EnricherSpec.create(Propagator.class)
+                    .configure(MutableMap.builder()
+                            .put(Propagator.PRODUCER, entity)
+                            .put(Propagator.PROPAGATING, ImmutableList.of(TestEntity.NAME))
+                            .put(Propagator.PROPAGATING_ALL, true)
+                            .build()));
+        } catch (Exception e) {
+            IllegalStateException ise = Exceptions.getFirstThrowableOfType(e, IllegalStateException.class);
+            if (ise == null) throw e;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/enricher/stock/TransformingEnricherDeprecatedTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/enricher/stock/TransformingEnricherDeprecatedTest.groovy b/core/src/test/java/org/apache/brooklyn/enricher/stock/TransformingEnricherDeprecatedTest.groovy
new file mode 100644
index 0000000..d1f264d
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/enricher/stock/TransformingEnricherDeprecatedTest.groovy
@@ -0,0 +1,83 @@
+/*
+ * 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.enricher.stock
+
+import java.util.concurrent.Callable
+
+import org.apache.brooklyn.api.entity.EntitySpec
+import org.apache.brooklyn.api.sensor.AttributeSensor
+import org.apache.brooklyn.core.test.entity.TestApplication
+import org.apache.brooklyn.core.test.entity.TestEntity
+import org.apache.brooklyn.enricher.stock.SensorTransformingEnricher;
+import org.apache.brooklyn.core.entity.Entities
+import org.apache.brooklyn.core.location.SimulatedLocation
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor
+import org.apache.brooklyn.test.TestUtils
+import org.apache.brooklyn.util.collections.MutableMap
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+import org.testng.Assert
+import org.testng.annotations.AfterMethod
+import org.testng.annotations.BeforeMethod
+import org.testng.annotations.Test
+
+public class TransformingEnricherDeprecatedTest {
+
+    public static final Logger log = LoggerFactory.getLogger(TransformingEnricherDeprecatedTest.class);
+            
+    private static final long TIMEOUT_MS = 10*1000;
+//    private static final long SHORT_WAIT_MS = 250;
+    
+    TestApplication app;
+    TestEntity producer;
+    AttributeSensor<Integer> intSensorA;
+    AttributeSensor<Long> target;
+
+    @BeforeMethod()
+    public void before() {
+        app = TestApplication.Factory.newManagedInstanceForTests();
+        producer = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        intSensorA = new BasicAttributeSensor<Integer>(Integer.class, "int.sensor.a");
+        target = new BasicAttributeSensor<Long>(Long.class, "long.sensor.target");
+        
+        app.start(Arrays.asList(new SimulatedLocation()));
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void after() {
+        if (app!=null) Entities.destroyAll(app.getManagementContext());
+    }
+    
+    @Test
+    public void testTransformingEnricher() throws InterruptedException {
+        final SensorTransformingEnricher e1 = new SensorTransformingEnricher<Integer,Long>(intSensorA, target, 
+            { 2*it });
+        
+        producer.setAttribute(intSensorA, 3);
+        //ensure previous values get picked up
+        producer.addEnricher(e1);
+
+        TestUtils.assertEventually(MutableMap.of("timeout", TIMEOUT_MS), 
+                new Callable<Object>() { public Object call() {
+                    Assert.assertEquals(producer.getAttribute(target), (Long)((long)6));
+                    return null;
+                }});
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/enricher/stock/TransformingEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/enricher/stock/TransformingEnricherTest.java b/core/src/test/java/org/apache/brooklyn/enricher/stock/TransformingEnricherTest.java
new file mode 100644
index 0000000..ee8fc9e
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/enricher/stock/TransformingEnricherTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.enricher.stock;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.location.SimulatedLocation;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.enricher.stock.Enrichers;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.util.math.MathFunctions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+
+public class TransformingEnricherTest extends BrooklynAppUnitTestSupport {
+
+    public static final Logger log = LoggerFactory.getLogger(TransformingEnricherTest.class);
+            
+    TestEntity producer;
+    AttributeSensor<Integer> intSensorA;
+    AttributeSensor<Long> target;
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        producer = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        intSensorA = new BasicAttributeSensor<Integer>(Integer.class, "int.sensor.a");
+        target = new BasicAttributeSensor<Long>(Long.class, "long.sensor.target");
+        
+        app.start(ImmutableList.of(new SimulatedLocation()));
+    }
+    
+    @Test
+    public void testTransformingEnricher() throws Exception {
+        //ensure previous values get picked up
+        producer.setAttribute(intSensorA, 3);
+
+        producer.addEnricher(Enrichers.builder()
+                .transforming(intSensorA)
+                //.computing(MathFunctions.times(2)) // TODO calling it before "publishing" means it doesn't check return type!
+                .publishing(target)
+                .computing((Function)MathFunctions.times(2)) // TODO doesn't match strongly typed int->long
+                .build());
+
+        EntityTestUtils.assertAttributeEqualsEventually(producer, target, 6L);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/enricher/stock/YamlRollingTimeWindowMeanEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/enricher/stock/YamlRollingTimeWindowMeanEnricherTest.java b/core/src/test/java/org/apache/brooklyn/enricher/stock/YamlRollingTimeWindowMeanEnricherTest.java
new file mode 100644
index 0000000..af683ac
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/enricher/stock/YamlRollingTimeWindowMeanEnricherTest.java
@@ -0,0 +1,179 @@
+/*
+ * 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.enricher.stock;
+
+import static org.testng.Assert.assertEquals;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.mgmt.SubscriptionContext;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.EnricherSpec;
+import org.apache.brooklyn.core.entity.AbstractApplication;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicSensorEvent;
+import org.apache.brooklyn.enricher.stock.YamlRollingTimeWindowMeanEnricher;
+import org.apache.brooklyn.enricher.stock.YamlTimeWeightedDeltaEnricher;
+import org.apache.brooklyn.enricher.stock.YamlRollingTimeWindowMeanEnricher.ConfidenceQualifiedNumber;
+import org.apache.brooklyn.entity.stock.BasicEntity;
+import org.apache.brooklyn.util.time.Duration;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class YamlRollingTimeWindowMeanEnricherTest {
+    
+    AbstractApplication app;
+    
+    BasicEntity producer;
+
+    AttributeSensor<Integer> intSensor;
+    AttributeSensor<Double> avgSensor, deltaSensor;
+    
+    Duration timePeriod = Duration.ONE_SECOND;
+    
+    YamlTimeWeightedDeltaEnricher<Double> delta;
+    YamlRollingTimeWindowMeanEnricher<Double> averager;
+    
+    ConfidenceQualifiedNumber average;
+    SubscriptionContext subscription;
+    
+    @SuppressWarnings("unchecked")
+    @BeforeMethod
+    public void before() {
+        app = new AbstractApplication() {};
+        Entities.startManagement(app);
+        producer = app.addChild(EntitySpec.create(BasicEntity.class));
+
+        intSensor = new BasicAttributeSensor<Integer>(Integer.class, "int sensor");
+        deltaSensor = new BasicAttributeSensor<Double>(Double.class, "delta sensor");
+        avgSensor = new BasicAttributeSensor<Double>(Double.class, "avg sensor");
+            
+        delta = producer.addEnricher(EnricherSpec.create(YamlTimeWeightedDeltaEnricher.class)
+                .configure(YamlTimeWeightedDeltaEnricher.PRODUCER, producer)
+                .configure(YamlTimeWeightedDeltaEnricher.SOURCE_SENSOR, intSensor)
+                .configure(YamlTimeWeightedDeltaEnricher.TARGET_SENSOR, deltaSensor));
+
+        averager = producer.addEnricher(EnricherSpec.create(YamlRollingTimeWindowMeanEnricher.class)
+                .configure(YamlRollingTimeWindowMeanEnricher.PRODUCER, producer)
+                .configure(YamlRollingTimeWindowMeanEnricher.SOURCE_SENSOR, deltaSensor)
+                .configure(YamlRollingTimeWindowMeanEnricher.TARGET_SENSOR, avgSensor)
+                .configure(YamlRollingTimeWindowMeanEnricher.WINDOW_DURATION, timePeriod));
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+        
+    @Test
+    public void testDefaultAverageWhenEmpty() {
+        ConfidenceQualifiedNumber average = averager.getAverage(0, 0);
+        assertEquals(average.value, 0d);
+        assertEquals(average.confidence, 0.0d);
+    }
+    
+    protected BasicSensorEvent<Integer> newIntSensorEvent(int value, long timestamp) {
+        return new BasicSensorEvent<Integer>(intSensor, producer, value, timestamp);
+    }
+    protected BasicSensorEvent<Double> newDeltaSensorEvent(double value, long timestamp) {
+        return new BasicSensorEvent<Double>(deltaSensor, producer, value, timestamp);
+    }
+
+    @Test
+    public void testNoRecentValuesAverage() {
+        averager.onEvent(newDeltaSensorEvent(10, 0));
+        average = averager.getAverage(timePeriod.toMilliseconds()+1000, 0);
+        assertEquals(average.value, 10d);
+        assertEquals(average.confidence, 0d);
+    }
+
+    @Test
+    public void testNoRecentValuesUsesLastForAverage() {
+        averager.onEvent(newDeltaSensorEvent(10, 0));
+        averager.onEvent(newDeltaSensorEvent(20, 10));
+        average = averager.getAverage(timePeriod.toMilliseconds()+1000, 0);
+        assertEquals(average.value, 20d);
+        assertEquals(average.confidence, 0d);
+    }
+
+    @Test
+    public void testSingleValueTimeAverage() {
+        averager.onEvent(newDeltaSensorEvent(10, 1000));
+        average = averager.getAverage(1000, 0);
+        assertEquals(average.confidence, 0d);
+    }
+
+    @Test
+    public void testTwoValueAverageForPeriod() {
+        averager.onEvent(newDeltaSensorEvent(10, 1000));
+        averager.onEvent(newDeltaSensorEvent(10, 2000));
+        average = averager.getAverage(2000, 0);
+        assertEquals(average.value, 10 /1d);
+        assertEquals(average.confidence, 1d);
+    }
+
+    @Test
+    public void testMonospacedAverage() {
+        averager.onEvent(newDeltaSensorEvent(10, 1000));
+        averager.onEvent(newDeltaSensorEvent(20, 1250));
+        averager.onEvent(newDeltaSensorEvent(30, 1500));
+        averager.onEvent(newDeltaSensorEvent(40, 1750));
+        averager.onEvent(newDeltaSensorEvent(50, 2000));
+        average = averager.getAverage(2000, 0);
+        assertEquals(average.value, (20+30+40+50)/4d);
+        assertEquals(average.confidence, 1d);
+    }
+
+    @Test
+    public void testWeightedAverage() {
+        averager.onEvent(newDeltaSensorEvent(10, 1000));
+        averager.onEvent(newDeltaSensorEvent(20, 1100));
+        averager.onEvent(newDeltaSensorEvent(30, 1300));
+        averager.onEvent(newDeltaSensorEvent(40, 1600));
+        averager.onEvent(newDeltaSensorEvent(50, 2000));
+        
+        average = averager.getAverage(2000, 0);
+        assertEquals(average.value, (20*0.1d)+(30*0.2d)+(40*0.3d)+(50*0.4d));
+        assertEquals(average.confidence, 1d);
+    }
+
+    @Test
+    public void testConfidenceDecay() {
+        averager.onEvent(newDeltaSensorEvent(10, 1000));
+        averager.onEvent(newDeltaSensorEvent(20, 1250));
+        averager.onEvent(newDeltaSensorEvent(30, 1500));
+        averager.onEvent(newDeltaSensorEvent(40, 1750));
+        averager.onEvent(newDeltaSensorEvent(50, 2000));
+
+        average = averager.getAverage(2250, 0);
+        assertEquals(average.value, (30+40+50)/3d);
+        assertEquals(average.confidence, 0.75d);
+        average = averager.getAverage(2500, 0);
+        assertEquals(average.value, (40+50)/2d);
+        assertEquals(average.confidence, 0.5d);
+        average = averager.getAverage(2750, 0);
+        assertEquals(average.value, 50d);
+        assertEquals(average.confidence, 0.25d);
+        average = averager.getAverage(3000, 0);
+        assertEquals(average.value, 50d);
+        assertEquals(average.confidence, 0d);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/enricher/stock/YamlTimeWeightedDeltaEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/enricher/stock/YamlTimeWeightedDeltaEnricherTest.java b/core/src/test/java/org/apache/brooklyn/enricher/stock/YamlTimeWeightedDeltaEnricherTest.java
new file mode 100644
index 0000000..41b75a7
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/enricher/stock/YamlTimeWeightedDeltaEnricherTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.enricher.stock;
+
+import static org.testng.Assert.assertEquals;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.mgmt.SubscriptionContext;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.EnricherSpec;
+import org.apache.brooklyn.core.entity.AbstractApplication;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicSensorEvent;
+import org.apache.brooklyn.enricher.stock.YamlTimeWeightedDeltaEnricher;
+import org.apache.brooklyn.entity.stock.BasicEntity;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class YamlTimeWeightedDeltaEnricherTest {
+    
+    AbstractApplication app;
+    
+    BasicEntity producer;
+
+    AttributeSensor<Integer> intSensor;
+    AttributeSensor<Double> avgSensor, deltaSensor;
+    SubscriptionContext subscription;
+    
+    @BeforeMethod
+    public void before() {
+        app = new AbstractApplication() {};
+        Entities.startManagement(app);
+        producer = app.addChild(EntitySpec.create(BasicEntity.class));
+
+        intSensor = new BasicAttributeSensor<Integer>(Integer.class, "int sensor");
+        deltaSensor = new BasicAttributeSensor<Double>(Double.class, "delta sensor");
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+    
+    @Test
+    public void testMonospaceTimeWeightedDeltaEnricher() {
+        @SuppressWarnings("unchecked")
+        YamlTimeWeightedDeltaEnricher<Integer> delta = producer.addEnricher(EnricherSpec.create(YamlTimeWeightedDeltaEnricher.class)
+            .configure(YamlTimeWeightedDeltaEnricher.PRODUCER, producer)
+            .configure(YamlTimeWeightedDeltaEnricher.SOURCE_SENSOR, intSensor)
+            .configure(YamlTimeWeightedDeltaEnricher.TARGET_SENSOR, deltaSensor));
+        
+        delta.onEvent(newIntSensorEvent(0, 0));
+        assertEquals(producer.getAttribute(deltaSensor), null);
+        delta.onEvent(newIntSensorEvent(0, 1000));
+        assertEquals(producer.getAttribute(deltaSensor), 0d);
+        delta.onEvent(newIntSensorEvent(1, 2000));
+        assertEquals(producer.getAttribute(deltaSensor), 1d);
+        delta.onEvent(newIntSensorEvent(3, 3000));
+        assertEquals(producer.getAttribute(deltaSensor), 2d);
+        delta.onEvent(newIntSensorEvent(8, 4000));
+        assertEquals(producer.getAttribute(deltaSensor), 5d);
+    }
+    
+    protected BasicSensorEvent<Integer> newIntSensorEvent(int value, long timestamp) {
+        return new BasicSensorEvent<Integer>(intSensor, producer, value, timestamp);
+    }
+    
+    @Test
+    public void testVariableTimeWeightedDeltaEnricher() {
+        @SuppressWarnings("unchecked")
+        YamlTimeWeightedDeltaEnricher<Integer> delta = producer.addEnricher(EnricherSpec.create(YamlTimeWeightedDeltaEnricher.class)
+            .configure(YamlTimeWeightedDeltaEnricher.PRODUCER, producer)
+            .configure(YamlTimeWeightedDeltaEnricher.SOURCE_SENSOR, intSensor)
+            .configure(YamlTimeWeightedDeltaEnricher.TARGET_SENSOR, deltaSensor));
+        
+        delta.onEvent(newIntSensorEvent(0, 0));
+        delta.onEvent(newIntSensorEvent(0, 2000));
+        assertEquals(producer.getAttribute(deltaSensor), 0d);
+        delta.onEvent(newIntSensorEvent(3, 5000));
+        assertEquals(producer.getAttribute(deltaSensor), 1d);
+        delta.onEvent(newIntSensorEvent(7, 7000));
+        assertEquals(producer.getAttribute(deltaSensor), 2d);
+        delta.onEvent(newIntSensorEvent(12, 7500));
+        assertEquals(producer.getAttribute(deltaSensor), 10d);
+        delta.onEvent(newIntSensorEvent(15, 9500));
+        assertEquals(producer.getAttribute(deltaSensor), 1.5d);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/sensor/enricher/BasicEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/enricher/BasicEnricherTest.java b/core/src/test/java/org/apache/brooklyn/sensor/enricher/BasicEnricherTest.java
deleted file mode 100644
index 04c183f..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/enricher/BasicEnricherTest.java
+++ /dev/null
@@ -1,119 +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 org.testng.Assert.assertEquals;
-
-import java.util.Map;
-
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.sensor.Enricher;
-import org.apache.brooklyn.api.sensor.EnricherSpec;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.BasicConfigKey;
-import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
-import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
-import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.apache.brooklyn.core.test.entity.TestApplicationNoEnrichersImpl;
-import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
-import org.apache.brooklyn.util.collections.MutableSet;
-import org.apache.brooklyn.util.core.flags.SetFromFlag;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.Iterables;
-
-/**
- * Test that enricher can be created and accessed, by construction and by spec
- */
-public class BasicEnricherTest extends BrooklynAppUnitTestSupport {
-    
-    // TODO These tests are a copy of BasicPolicyTest, which is a code smell.
-    // However, the src/main/java code does not contain as much duplication.
-
-    protected void setUpApp() {
-        EntitySpec<TestApplication> appSpec = EntitySpec.create(TestApplication.class, TestApplicationNoEnrichersImpl.class)
-                .configure(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, shouldSkipOnBoxBaseDirResolution());
-        app = ApplicationBuilder.newManagedApp(appSpec, mgmt);
-    }
-
-    public static class MyEnricher extends AbstractEnricher {
-        @SetFromFlag("intKey")
-        public static final BasicConfigKey<Integer> INT_KEY = new BasicConfigKey<Integer>(Integer.class, "bkey", "b key");
-        
-        @SetFromFlag("strKey")
-        public static final ConfigKey<String> STR_KEY = new BasicConfigKey<String>(String.class, "akey", "a key");
-        public static final ConfigKey<Integer> INT_KEY_WITH_DEFAULT = new BasicConfigKey<Integer>(Integer.class, "ckey", "c key", 1);
-        public static final ConfigKey<String> STR_KEY_WITH_DEFAULT = new BasicConfigKey<String>(String.class, "strKey", "str key", "str key default");
-        
-        MyEnricher(Map<?,?> flags) {
-            super(flags);
-        }
-        
-        public MyEnricher() {
-            super();
-        }
-    }
-    
-    @Test
-    public void testAddInstance() throws Exception {
-        MyEnricher enricher = new MyEnricher();
-        enricher.setDisplayName("Bob");
-        enricher.config().set(MyEnricher.STR_KEY, "aval");
-        enricher.config().set(MyEnricher.INT_KEY, 2);
-        app.addEnricher(enricher);
-        
-        assertEquals(enricher.getDisplayName(), "Bob");
-        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval");
-        assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2);
-    }
-    
-    @Test
-    public void testAddSpec() throws Exception {
-        MyEnricher enricher = app.addEnricher(EnricherSpec.create(MyEnricher.class)
-            .displayName("Bob")
-            .configure(MyEnricher.STR_KEY, "aval").configure(MyEnricher.INT_KEY, 2));
-        
-        assertEquals(enricher.getDisplayName(), "Bob");
-        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval");
-        assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2);
-    }
-        
-    @Test
-    public void testTagsFromSpec() throws Exception {
-        MyEnricher enricher = app.addEnricher(EnricherSpec.create(MyEnricher.class).tag(99).uniqueTag("x"));
-
-        assertEquals(enricher.tags().getTags(), MutableSet.of("x", 99));
-        assertEquals(enricher.getUniqueTag(), "x");
-    }
-
-    @Test
-    public void testSameUniqueTagEnricherNotAddedTwice() throws Exception {
-        app.addEnricher(EnricherSpec.create(MyEnricher.class).tag(99).uniqueTag("x"));
-        app.addEnricher(EnricherSpec.create(MyEnricher.class).tag(94).uniqueTag("x"));
-        
-        assertEquals(app.getEnrichers().size(), 1);
-        // the more recent one should dominate
-        Enricher enricher = Iterables.getOnlyElement(app.getEnrichers());
-        Assert.assertTrue(enricher.tags().containsTag(94));
-        Assert.assertFalse(enricher.tags().containsTag(99));
-    }
-
-}


[12/36] incubator-brooklyn git commit: Rename o.a.b.sensor.core to o.a.b.core.sensor

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/sensor/feed/http/HttpFeedIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/feed/http/HttpFeedIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/sensor/feed/http/HttpFeedIntegrationTest.java
index 9e322fb..475490b 100644
--- a/core/src/test/java/org/apache/brooklyn/sensor/feed/http/HttpFeedIntegrationTest.java
+++ b/core/src/test/java/org/apache/brooklyn/sensor/feed/http/HttpFeedIntegrationTest.java
@@ -28,10 +28,10 @@ import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.HttpService;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.feed.http.HttpFeed;
 import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
 import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/sensor/feed/http/HttpFeedTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/feed/http/HttpFeedTest.java b/core/src/test/java/org/apache/brooklyn/sensor/feed/http/HttpFeedTest.java
index 14d9ce1..f04c855 100644
--- a/core/src/test/java/org/apache/brooklyn/sensor/feed/http/HttpFeedTest.java
+++ b/core/src/test/java/org/apache/brooklyn/sensor/feed/http/HttpFeedTest.java
@@ -33,9 +33,9 @@ import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityFunctions;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.EntityInternal.FeedSupport;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.feed.FeedConfig;
 import org.apache.brooklyn.sensor.feed.PollConfig;
 import org.apache.brooklyn.sensor.feed.http.HttpFeed;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/sensor/feed/shell/ShellFeedIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/feed/shell/ShellFeedIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/sensor/feed/shell/ShellFeedIntegrationTest.java
index 9406e8a..b274cbc 100644
--- a/core/src/test/java/org/apache/brooklyn/sensor/feed/shell/ShellFeedIntegrationTest.java
+++ b/core/src/test/java/org/apache/brooklyn/sensor/feed/shell/ShellFeedIntegrationTest.java
@@ -28,9 +28,9 @@ import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.EntityInternal.FeedSupport;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.feed.function.FunctionFeedTest;
 import org.apache.brooklyn.sensor.feed.shell.ShellFeed;
 import org.apache.brooklyn.sensor.feed.shell.ShellFeedIntegrationTest;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/sensor/feed/ssh/SshFeedIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/feed/ssh/SshFeedIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/sensor/feed/ssh/SshFeedIntegrationTest.java
index d26334f..de9d5f1 100644
--- a/core/src/test/java/org/apache/brooklyn/sensor/feed/ssh/SshFeedIntegrationTest.java
+++ b/core/src/test/java/org/apache/brooklyn/sensor/feed/ssh/SshFeedIntegrationTest.java
@@ -29,9 +29,9 @@ import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.EntityInternal.FeedSupport;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.feed.ssh.SshFeed;
 import org.apache.brooklyn.sensor.feed.ssh.SshFeedIntegrationTest;
 import org.apache.brooklyn.sensor.feed.ssh.SshPollConfig;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeedLiveTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeedLiveTest.java b/core/src/test/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeedLiveTest.java
index 0ec3d51..42a25c0 100644
--- a/core/src/test/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeedLiveTest.java
+++ b/core/src/test/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeedLiveTest.java
@@ -26,9 +26,9 @@ import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.feed.windows.WindowsPerformanceCounterFeed;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.collections.MutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeedTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeedTest.java b/core/src/test/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeedTest.java
index f8baf7f..9a27e8e 100644
--- a/core/src/test/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeedTest.java
+++ b/core/src/test/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeedTest.java
@@ -30,9 +30,9 @@ import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.feed.windows.WindowsPerformanceCounterFeed;
 import org.apache.brooklyn.sensor.feed.windows.WindowsPerformanceCounterPollConfig;
 import org.apache.brooklyn.test.EntityTestUtils;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/util/core/task/TasksTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/task/TasksTest.java b/core/src/test/java/org/apache/brooklyn/util/core/task/TasksTest.java
index 844fd72..4d1e6e1 100644
--- a/core/src/test/java/org/apache/brooklyn/util/core/task/TasksTest.java
+++ b/core/src/test/java/org/apache/brooklyn/util/core/task/TasksTest.java
@@ -18,7 +18,7 @@
  */
 package org.apache.brooklyn.util.core.task;
 
-import static org.apache.brooklyn.sensor.core.DependentConfiguration.attributeWhenReady;
+import static org.apache.brooklyn.core.sensor.DependentConfiguration.attributeWhenReady;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertTrue;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/util/core/text/TemplateProcessorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/text/TemplateProcessorTest.java b/core/src/test/java/org/apache/brooklyn/util/core/text/TemplateProcessorTest.java
index 217659b..52535da 100644
--- a/core/src/test/java/org/apache/brooklyn/util/core/text/TemplateProcessorTest.java
+++ b/core/src/test/java/org/apache/brooklyn/util/core/text/TemplateProcessorTest.java
@@ -22,10 +22,10 @@ import static org.testng.Assert.assertEquals;
 
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
 import org.apache.brooklyn.test.FixedLocaleTest;
 import org.apache.brooklyn.util.core.text.TemplateProcessor;
 import org.testng.Assert;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/examples/global-web-fabric/src/main/java/org/apache/brooklyn/demo/GlobalWebFabricExample.java
----------------------------------------------------------------------
diff --git a/examples/global-web-fabric/src/main/java/org/apache/brooklyn/demo/GlobalWebFabricExample.java b/examples/global-web-fabric/src/main/java/org/apache/brooklyn/demo/GlobalWebFabricExample.java
index c83d1d0..99faf04 100644
--- a/examples/global-web-fabric/src/main/java/org/apache/brooklyn/demo/GlobalWebFabricExample.java
+++ b/examples/global-web-fabric/src/main/java/org/apache/brooklyn/demo/GlobalWebFabricExample.java
@@ -35,13 +35,13 @@ import org.apache.brooklyn.core.entity.AbstractApplication;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.StartableApplication;
 import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.dns.geoscaling.GeoscalingDnsService;
 import org.apache.brooklyn.entity.group.DynamicRegionsFabric;
 import org.apache.brooklyn.entity.proxy.AbstractController;
 import org.apache.brooklyn.entity.webapp.ElasticJavaWebAppService;
 import org.apache.brooklyn.entity.webapp.JavaWebAppService;
 import org.apache.brooklyn.launcher.BrooklynLauncher;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.CommandLineUtil;
 import org.apache.brooklyn.util.core.BrooklynMavenArtifacts;
 import org.apache.brooklyn.util.core.ResourceUtils;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/CumulusRDFApplication.java
----------------------------------------------------------------------
diff --git a/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/CumulusRDFApplication.java b/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/CumulusRDFApplication.java
index bc3671f..4c0b87e 100644
--- a/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/CumulusRDFApplication.java
+++ b/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/CumulusRDFApplication.java
@@ -47,6 +47,7 @@ import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.entity.java.UsesJava;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.entity.nosql.cassandra.CassandraDatacenter;
@@ -58,7 +59,6 @@ import org.apache.brooklyn.launcher.BrooklynLauncher;
 import org.apache.brooklyn.policy.ha.ServiceFailureDetector;
 import org.apache.brooklyn.policy.ha.ServiceReplacer;
 import org.apache.brooklyn.policy.ha.ServiceRestarter;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
 import org.apache.brooklyn.util.CommandLineUtil;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/NodeJsTodoApplication.java
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/NodeJsTodoApplication.java b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/NodeJsTodoApplication.java
index 5ce062a..086f390 100644
--- a/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/NodeJsTodoApplication.java
+++ b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/NodeJsTodoApplication.java
@@ -18,7 +18,7 @@
  */
 package org.apache.brooklyn.demo;
 
-import static org.apache.brooklyn.sensor.core.DependentConfiguration.attributeWhenReady;
+import static org.apache.brooklyn.core.sensor.DependentConfiguration.attributeWhenReady;
 
 import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.EntitySpec;
@@ -26,10 +26,10 @@ import org.apache.brooklyn.core.entity.AbstractApplication;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.StartableApplication;
 import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.entity.nosql.redis.RedisStore;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.webapp.nodejs.NodeJsWebAppService;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExample.java
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExample.java b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExample.java
index da1074e..6c56b5f 100644
--- a/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExample.java
+++ b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExample.java
@@ -18,9 +18,9 @@
  */
 package org.apache.brooklyn.demo;
 
+import static org.apache.brooklyn.core.sensor.DependentConfiguration.attributeWhenReady;
+import static org.apache.brooklyn.core.sensor.DependentConfiguration.formatString;
 import static org.apache.brooklyn.entity.java.JavaEntityMethods.javaSysProp;
-import static org.apache.brooklyn.sensor.core.DependentConfiguration.attributeWhenReady;
-import static org.apache.brooklyn.sensor.core.DependentConfiguration.formatString;
 
 import java.util.List;
 import java.util.concurrent.TimeUnit;
@@ -34,6 +34,7 @@ import org.apache.brooklyn.core.entity.AbstractApplication;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.StartableApplication;
 import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster;
 import org.apache.brooklyn.entity.webapp.DynamicWebAppCluster;
 import org.apache.brooklyn.entity.webapp.JavaWebAppService;
@@ -42,7 +43,6 @@ import org.apache.brooklyn.entity.webapp.WebAppServiceConstants;
 import org.apache.brooklyn.launcher.BrooklynLauncher;
 import org.apache.brooklyn.policy.autoscaling.AutoScalerPolicy;
 import org.apache.brooklyn.policy.enricher.HttpLatencyDetector;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.CommandLineUtil;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExampleApp.java
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExampleApp.java b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExampleApp.java
index cff372c..ed8a987 100644
--- a/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExampleApp.java
+++ b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExampleApp.java
@@ -18,8 +18,8 @@
  */
 package org.apache.brooklyn.demo;
 
-import static org.apache.brooklyn.sensor.core.DependentConfiguration.attributeWhenReady;
-import static org.apache.brooklyn.sensor.core.DependentConfiguration.formatString;
+import static org.apache.brooklyn.core.sensor.DependentConfiguration.attributeWhenReady;
+import static org.apache.brooklyn.core.sensor.DependentConfiguration.formatString;
 
 import java.util.List;
 import java.util.concurrent.TimeUnit;
@@ -36,6 +36,7 @@ import org.apache.brooklyn.core.entity.AbstractApplication;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.StartableApplication;
 import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster;
 import org.apache.brooklyn.entity.webapp.DynamicWebAppCluster;
 import org.apache.brooklyn.entity.webapp.JavaWebAppService;
@@ -47,7 +48,6 @@ import org.apache.brooklyn.entity.java.JavaEntityMethods;
 import org.apache.brooklyn.launcher.BrooklynLauncher;
 import org.apache.brooklyn.policy.autoscaling.AutoScalerPolicy;
 import org.apache.brooklyn.policy.enricher.HttpLatencyDetector;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.CommandLineUtil;
 import org.apache.brooklyn.util.core.BrooklynMavenArtifacts;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExampleGroovy.groovy
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExampleGroovy.groovy b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExampleGroovy.groovy
index 8ec01e4..0f852c2 100644
--- a/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExampleGroovy.groovy
+++ b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExampleGroovy.groovy
@@ -19,8 +19,8 @@
 package org.apache.brooklyn.demo;
 
 import static org.apache.brooklyn.entity.java.JavaEntityMethods.javaSysProp
-import static org.apache.brooklyn.sensor.core.DependentConfiguration.attributeWhenReady
-import static org.apache.brooklyn.sensor.core.DependentConfiguration.formatString
+import static org.apache.brooklyn.core.sensor.DependentConfiguration.attributeWhenReady
+import static org.apache.brooklyn.core.sensor.DependentConfiguration.formatString
 
 import org.apache.brooklyn.api.entity.EntitySpec
 import org.apache.brooklyn.core.entity.AbstractApplication

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/locations/jclouds/src/main/java/org/apache/brooklyn/policy/jclouds/os/CreateUserPolicy.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/policy/jclouds/os/CreateUserPolicy.java b/locations/jclouds/src/main/java/org/apache/brooklyn/policy/jclouds/os/CreateUserPolicy.java
index 4b7e9c5..292a28a 100644
--- a/locations/jclouds/src/main/java/org/apache/brooklyn/policy/jclouds/os/CreateUserPolicy.java
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/policy/jclouds/os/CreateUserPolicy.java
@@ -31,8 +31,8 @@ import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.policy.AbstractPolicy;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.core.internal.ssh.SshTool;
 import org.apache.brooklyn.util.text.Identifiers;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/main/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicy.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicy.java b/policy/src/main/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicy.java
index 0956573..274aa9a 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicy.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicy.java
@@ -47,9 +47,9 @@ import org.apache.brooklyn.core.entity.trait.Resizable;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
 import org.apache.brooklyn.core.policy.AbstractPolicy;
+import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
 import org.apache.brooklyn.policy.autoscaling.SizeHistory.WindowSummary;
 import org.apache.brooklyn.policy.loadbalancing.LoadBalancingPolicy;
-import org.apache.brooklyn.sensor.core.BasicNotificationSensor;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.core.flags.TypeCoercions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/main/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetector.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetector.java b/policy/src/main/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetector.java
index cd23326..8c8f8f7 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetector.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetector.java
@@ -35,7 +35,7 @@ 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.trait.Startable;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
 import org.apache.brooklyn.sensor.feed.http.HttpFeed;
 import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/main/java/org/apache/brooklyn/policy/followthesun/FollowTheSunPool.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/followthesun/FollowTheSunPool.java b/policy/src/main/java/org/apache/brooklyn/policy/followthesun/FollowTheSunPool.java
index 39c1202..a5e6a1e 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/followthesun/FollowTheSunPool.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/followthesun/FollowTheSunPool.java
@@ -26,7 +26,7 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.Group;
 import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.core.entity.trait.Resizable;
-import org.apache.brooklyn.sensor.core.BasicNotificationSensor;
+import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
 
 @ImplementedBy(FollowTheSunPoolImpl.class)
 public interface FollowTheSunPool extends Entity, Resizable {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/main/java/org/apache/brooklyn/policy/ha/ConnectionFailureDetector.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/ha/ConnectionFailureDetector.java b/policy/src/main/java/org/apache/brooklyn/policy/ha/ConnectionFailureDetector.java
index 86b2027..a844e00 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/ha/ConnectionFailureDetector.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/ha/ConnectionFailureDetector.java
@@ -23,8 +23,8 @@ import org.apache.brooklyn.api.sensor.Sensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.BasicConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
 import org.apache.brooklyn.policy.ha.HASensors.FailureDescriptor;
-import org.apache.brooklyn.sensor.core.BasicNotificationSensor;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.net.Networking;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/main/java/org/apache/brooklyn/policy/ha/HASensors.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/ha/HASensors.java b/policy/src/main/java/org/apache/brooklyn/policy/ha/HASensors.java
index 02824fc..6ba1a08 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/ha/HASensors.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/ha/HASensors.java
@@ -18,7 +18,7 @@
  */
 package org.apache.brooklyn.policy.ha;
 
-import org.apache.brooklyn.sensor.core.BasicNotificationSensor;
+import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
 
 import com.google.common.base.Objects;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java b/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java
index ce6eb86..195886d 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java
@@ -32,10 +32,10 @@ import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ComputeServiceState;
+import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.policy.ha.HASensors.FailureDescriptor;
-import org.apache.brooklyn.sensor.core.BasicNotificationSensor;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceReplacer.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceReplacer.java b/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceReplacer.java
index 5e036e1..5d66b85 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceReplacer.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceReplacer.java
@@ -43,9 +43,9 @@ import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceProblemsLogic;
 import org.apache.brooklyn.core.entity.trait.MemberReplaceable;
 import org.apache.brooklyn.core.policy.AbstractPolicy;
+import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
 import org.apache.brooklyn.entity.group.StopFailedRuntimeException;
 import org.apache.brooklyn.policy.ha.HASensors.FailureDescriptor;
-import org.apache.brooklyn.sensor.core.BasicNotificationSensor;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceRestarter.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceRestarter.java b/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceRestarter.java
index 37ce701..3d5f84d 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceRestarter.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceRestarter.java
@@ -36,8 +36,8 @@ import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.policy.AbstractPolicy;
+import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
 import org.apache.brooklyn.policy.ha.HASensors.FailureDescriptor;
-import org.apache.brooklyn.sensor.core.BasicNotificationSensor;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/main/java/org/apache/brooklyn/policy/ha/SshMachineFailureDetector.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/ha/SshMachineFailureDetector.java b/policy/src/main/java/org/apache/brooklyn/policy/ha/SshMachineFailureDetector.java
index 12a1e4c..e5da346 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/ha/SshMachineFailureDetector.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/ha/SshMachineFailureDetector.java
@@ -26,9 +26,9 @@ import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.location.Machines;
+import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.policy.ha.HASensors.FailureDescriptor;
-import org.apache.brooklyn.sensor.core.BasicNotificationSensor;
 import org.apache.brooklyn.util.core.internal.ssh.SshTool;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/main/java/org/apache/brooklyn/policy/loadbalancing/BalanceableContainer.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/loadbalancing/BalanceableContainer.java b/policy/src/main/java/org/apache/brooklyn/policy/loadbalancing/BalanceableContainer.java
index 80896de..94887cf 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/loadbalancing/BalanceableContainer.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/loadbalancing/BalanceableContainer.java
@@ -23,8 +23,8 @@ import java.util.Set;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
 import org.apache.brooklyn.entity.group.AbstractGroup;
-import org.apache.brooklyn.sensor.core.BasicNotificationSensor;
 import org.apache.brooklyn.util.collections.QuorumCheck;
 import org.apache.brooklyn.util.collections.QuorumCheck.QuorumChecks;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/main/java/org/apache/brooklyn/policy/loadbalancing/BalanceableWorkerPool.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/loadbalancing/BalanceableWorkerPool.java b/policy/src/main/java/org/apache/brooklyn/policy/loadbalancing/BalanceableWorkerPool.java
index 62059e5..d34fdc7 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/loadbalancing/BalanceableWorkerPool.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/loadbalancing/BalanceableWorkerPool.java
@@ -26,7 +26,7 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.Group;
 import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.core.entity.trait.Resizable;
-import org.apache.brooklyn.sensor.core.BasicNotificationSensor;
+import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
 
 /**
  * Represents an elastic group of "container" entities, each of which is capable of hosting "item" entities that perform

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/main/java/org/apache/brooklyn/policy/loadbalancing/Movable.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/loadbalancing/Movable.java b/policy/src/main/java/org/apache/brooklyn/policy/loadbalancing/Movable.java
index bec64cc..44797cf 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/loadbalancing/Movable.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/loadbalancing/Movable.java
@@ -24,7 +24,7 @@ import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.annotation.EffectorParam;
 import org.apache.brooklyn.core.config.BasicConfigKey;
 import org.apache.brooklyn.core.effector.MethodEffector;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyMetricTest.java
----------------------------------------------------------------------
diff --git a/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyMetricTest.java b/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyMetricTest.java
index 39aeb8e..f9c2961 100644
--- a/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyMetricTest.java
+++ b/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyMetricTest.java
@@ -30,11 +30,11 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.SensorEvent;
 import org.apache.brooklyn.api.sensor.SensorEventListener;
 import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestCluster;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.core.BasicNotificationSensor;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.test.Asserts;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyRebindTest.java
----------------------------------------------------------------------
diff --git a/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyRebindTest.java b/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyRebindTest.java
index c6ac315..a0b7451 100644
--- a/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyRebindTest.java
+++ b/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyRebindTest.java
@@ -29,11 +29,11 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.location.SimulatedLocation;
 import org.apache.brooklyn.core.mgmt.rebind.RebindTestFixtureWithApp;
+import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.sensor.core.BasicNotificationSensor;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.time.Duration;
 import org.testng.annotations.BeforeMethod;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyReconfigurationTest.java
----------------------------------------------------------------------
diff --git a/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyReconfigurationTest.java b/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyReconfigurationTest.java
index aeb09a0..9637235 100644
--- a/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyReconfigurationTest.java
+++ b/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyReconfigurationTest.java
@@ -23,9 +23,9 @@ import static org.apache.brooklyn.policy.autoscaling.AutoScalerPolicyTest.curren
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestCluster;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.time.Duration;
 import org.testng.annotations.AfterMethod;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyTest.java
----------------------------------------------------------------------
diff --git a/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyTest.java b/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyTest.java
index bb9b247..9cd149a 100644
--- a/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyTest.java
+++ b/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyTest.java
@@ -37,9 +37,9 @@ import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.policy.PolicySpec;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.trait.Resizable;
+import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestCluster;
-import org.apache.brooklyn.sensor.core.BasicNotificationSensor;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/test/java/org/apache/brooklyn/policy/enricher/DeltaEnrichersTests.groovy
----------------------------------------------------------------------
diff --git a/policy/src/test/java/org/apache/brooklyn/policy/enricher/DeltaEnrichersTests.groovy b/policy/src/test/java/org/apache/brooklyn/policy/enricher/DeltaEnrichersTests.groovy
index 2e7588c..2004ebd 100644
--- a/policy/src/test/java/org/apache/brooklyn/policy/enricher/DeltaEnrichersTests.groovy
+++ b/policy/src/test/java/org/apache/brooklyn/policy/enricher/DeltaEnrichersTests.groovy
@@ -26,7 +26,7 @@ import org.apache.brooklyn.api.sensor.Sensor
 import org.apache.brooklyn.core.entity.AbstractApplication
 import org.apache.brooklyn.core.entity.AbstractEntity
 import org.apache.brooklyn.core.entity.Entities
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor
 import org.testng.annotations.AfterMethod
 import org.testng.annotations.BeforeMethod
 import org.testng.annotations.Test

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/test/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetectorTest.java
----------------------------------------------------------------------
diff --git a/policy/src/test/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetectorTest.java b/policy/src/test/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetectorTest.java
index 76cebbf..0aeac73 100644
--- a/policy/src/test/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetectorTest.java
+++ b/policy/src/test/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetectorTest.java
@@ -25,10 +25,10 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.policy.enricher.HttpLatencyDetector;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.http.BetterMockWebServer;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/test/java/org/apache/brooklyn/policy/enricher/RebindEnricherTest.java
----------------------------------------------------------------------
diff --git a/policy/src/test/java/org/apache/brooklyn/policy/enricher/RebindEnricherTest.java b/policy/src/test/java/org/apache/brooklyn/policy/enricher/RebindEnricherTest.java
index b12788a..7f3dfb1 100644
--- a/policy/src/test/java/org/apache/brooklyn/policy/enricher/RebindEnricherTest.java
+++ b/policy/src/test/java/org/apache/brooklyn/policy/enricher/RebindEnricherTest.java
@@ -26,6 +26,7 @@ import java.util.concurrent.TimeUnit;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.mgmt.rebind.RebindTestFixtureWithApp;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.policy.enricher.DeltaEnricher;
 import org.apache.brooklyn.policy.enricher.HttpLatencyDetector;
@@ -33,7 +34,6 @@ import org.apache.brooklyn.policy.enricher.RollingMeanEnricher;
 import org.apache.brooklyn.policy.enricher.RollingTimeWindowMeanEnricher;
 import org.apache.brooklyn.policy.enricher.TimeFractionDeltaEnricher;
 import org.apache.brooklyn.policy.enricher.TimeWeightedDeltaEnricher;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.core.http.BetterMockWebServer;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingMeanEnricherTest.groovy
----------------------------------------------------------------------
diff --git a/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingMeanEnricherTest.groovy b/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingMeanEnricherTest.groovy
index 0dc6686..7e5ae62 100644
--- a/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingMeanEnricherTest.groovy
+++ b/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingMeanEnricherTest.groovy
@@ -26,7 +26,7 @@ import org.apache.brooklyn.api.sensor.Sensor
 import org.apache.brooklyn.core.entity.AbstractApplication
 import org.apache.brooklyn.core.entity.AbstractEntity
 import org.apache.brooklyn.core.entity.Entities
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor
 import org.testng.annotations.AfterMethod
 import org.testng.annotations.BeforeMethod
 import org.testng.annotations.Test

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricherTest.groovy
----------------------------------------------------------------------
diff --git a/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricherTest.groovy b/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricherTest.groovy
index 56d27ee..bd9c13f 100644
--- a/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricherTest.groovy
+++ b/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricherTest.groovy
@@ -26,8 +26,8 @@ import org.apache.brooklyn.api.sensor.Sensor
 import org.apache.brooklyn.core.entity.AbstractApplication
 import org.apache.brooklyn.core.entity.AbstractEntity
 import org.apache.brooklyn.core.entity.Entities
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor
 import org.apache.brooklyn.policy.enricher.RollingTimeWindowMeanEnricher.ConfidenceQualifiedNumber
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor
 import org.testng.annotations.AfterMethod
 import org.testng.annotations.BeforeMethod
 import org.testng.annotations.Test

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/test/java/org/apache/brooklyn/policy/enricher/TimeFractionDeltaEnricherTest.java
----------------------------------------------------------------------
diff --git a/policy/src/test/java/org/apache/brooklyn/policy/enricher/TimeFractionDeltaEnricherTest.java b/policy/src/test/java/org/apache/brooklyn/policy/enricher/TimeFractionDeltaEnricherTest.java
index 84562b2..bd18631 100644
--- a/policy/src/test/java/org/apache/brooklyn/policy/enricher/TimeFractionDeltaEnricherTest.java
+++ b/policy/src/test/java/org/apache/brooklyn/policy/enricher/TimeFractionDeltaEnricherTest.java
@@ -29,11 +29,11 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.Sensor;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
+import org.apache.brooklyn.core.sensor.BasicSensorEvent;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.policy.enricher.TimeFractionDeltaEnricher;
-import org.apache.brooklyn.sensor.core.BasicSensorEvent;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/test/java/org/apache/brooklyn/policy/loadbalancing/AbstractLoadBalancingPolicyTest.java
----------------------------------------------------------------------
diff --git a/policy/src/test/java/org/apache/brooklyn/policy/loadbalancing/AbstractLoadBalancingPolicyTest.java b/policy/src/test/java/org/apache/brooklyn/policy/loadbalancing/AbstractLoadBalancingPolicyTest.java
index fb714ad..eebf16e 100644
--- a/policy/src/test/java/org/apache/brooklyn/policy/loadbalancing/AbstractLoadBalancingPolicyTest.java
+++ b/policy/src/test/java/org/apache/brooklyn/policy/loadbalancing/AbstractLoadBalancingPolicyTest.java
@@ -35,9 +35,9 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.BasicConfigKey;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.SimulatedLocation;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.entity.group.DynamicGroup;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.time.Time;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/policy/src/test/java/org/apache/brooklyn/policy/loadbalancing/MockItemEntity.java
----------------------------------------------------------------------
diff --git a/policy/src/test/java/org/apache/brooklyn/policy/loadbalancing/MockItemEntity.java b/policy/src/test/java/org/apache/brooklyn/policy/loadbalancing/MockItemEntity.java
index 0cf1ca7..c2689a3 100644
--- a/policy/src/test/java/org/apache/brooklyn/policy/loadbalancing/MockItemEntity.java
+++ b/policy/src/test/java/org/apache/brooklyn/policy/loadbalancing/MockItemEntity.java
@@ -23,7 +23,7 @@ import java.util.Map;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.Sensors;
 
 import com.google.common.reflect.TypeToken;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/derby/DerbyDatabase.java
----------------------------------------------------------------------
diff --git a/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/derby/DerbyDatabase.java b/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/derby/DerbyDatabase.java
index e9e3b6a..ffa8bd6 100644
--- a/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/derby/DerbyDatabase.java
+++ b/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/derby/DerbyDatabase.java
@@ -32,13 +32,13 @@ import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
 import org.apache.brooklyn.entity.java.UsesJava;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.core.config.BasicConfigKey;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.sensor.feed.jmx.JmxHelper;
 import org.apache.brooklyn.util.collections.MutableMap;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/derby/DerbySchema.java
----------------------------------------------------------------------
diff --git a/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/derby/DerbySchema.java b/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/derby/DerbySchema.java
index 5b9c7eb..23cfb2c 100644
--- a/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/derby/DerbySchema.java
+++ b/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/derby/DerbySchema.java
@@ -26,6 +26,7 @@ import java.util.concurrent.TimeUnit;
 import javax.management.ObjectName;
 
 import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.entity.database.Schema;
 
@@ -33,7 +34,6 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
 import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;
 import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
 import org.apache.brooklyn.sensor.feed.jmx.JmxHelper;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/sandbox/extra/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeSaltImpl.java
----------------------------------------------------------------------
diff --git a/sandbox/extra/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeSaltImpl.java b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeSaltImpl.java
index ace9a62..0070b39 100644
--- a/sandbox/extra/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeSaltImpl.java
+++ b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeSaltImpl.java
@@ -37,10 +37,10 @@ import org.apache.brooklyn.core.effector.EffectorBody;
 import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.entity.stock.EffectorStartableImpl;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.database.postgresql.PostgreSqlNode;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
 import org.apache.brooklyn.sensor.feed.ssh.SshFeed;
 import org.apache.brooklyn.sensor.feed.ssh.SshPollConfig;
 import org.apache.brooklyn.util.ssh.BashCommands;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltConfig.java
----------------------------------------------------------------------
diff --git a/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltConfig.java b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltConfig.java
index cebded8..c67eda0 100644
--- a/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltConfig.java
+++ b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltConfig.java
@@ -26,10 +26,10 @@ import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
 import org.apache.brooklyn.core.config.BasicConfigKey;
 import org.apache.brooklyn.core.config.MapConfigKey;
 import org.apache.brooklyn.core.config.SetConfigKey;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Function;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltStackMaster.java
----------------------------------------------------------------------
diff --git a/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltStackMaster.java b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltStackMaster.java
index a90b836..5b4a085 100644
--- a/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltStackMaster.java
+++ b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltStackMaster.java
@@ -29,9 +29,9 @@ import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
 
 import com.google.common.reflect.TypeToken;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixMonitored.java
----------------------------------------------------------------------
diff --git a/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixMonitored.java b/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixMonitored.java
index 12d7bac..deb8bf1 100644
--- a/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixMonitored.java
+++ b/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixMonitored.java
@@ -21,8 +21,8 @@ package org.apache.brooklyn.entity.monitoring.zabbix;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.BasicConfigKey;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 public interface ZabbixMonitored {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixServer.java
----------------------------------------------------------------------
diff --git a/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixServer.java b/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixServer.java
index 861d103..9ecaada 100644
--- a/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixServer.java
+++ b/sandbox/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/zabbix/ZabbixServer.java
@@ -23,7 +23,7 @@ import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.BasicConfigKey;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 import com.google.common.base.Predicate;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastCluster.java
----------------------------------------------------------------------
diff --git a/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastCluster.java b/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastCluster.java
index d64cd3c..c43e882 100644
--- a/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastCluster.java
+++ b/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastCluster.java
@@ -29,9 +29,9 @@ import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
 
 /**
  * A cluster of {@link HazelcastNode}s based on {@link DynamicCluster}.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNode.java
----------------------------------------------------------------------
diff --git a/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNode.java b/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNode.java
index 54bce7e..e53d0da 100644
--- a/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNode.java
+++ b/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNode.java
@@ -24,12 +24,12 @@ import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.java.UsesJava;
 import org.apache.brooklyn.entity.java.UsesJmx;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.javalang.JavaClassNames;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5Server.java
----------------------------------------------------------------------
diff --git a/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5Server.java b/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5Server.java
index 7d62229..7ec7bb4 100644
--- a/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5Server.java
+++ b/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5Server.java
@@ -27,11 +27,11 @@ import org.slf4j.LoggerFactory;
 
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
 import org.apache.brooklyn.entity.java.UsesJmx;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.collections.MutableMap;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynCluster.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynCluster.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynCluster.java
index f00b4db..8052037 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynCluster.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynCluster.java
@@ -27,9 +27,9 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.effector.Effectors;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.brooklynnode.effector.BrooklynNodeUpgradeEffectorBody;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.sensor.core.Sensors;
 
 @ImplementedBy(BrooklynClusterImpl.class)
 public interface BrooklynCluster extends DynamicCluster {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynEntityMirror.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynEntityMirror.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynEntityMirror.java
index ac884fa..7ccdda9 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynEntityMirror.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynEntityMirror.java
@@ -26,8 +26,8 @@ import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.time.Duration;
 
 /** Provides an entity which can sit in one brooklyn domain and reflect the status of an entity 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java
index 0a99d1f..91622dd 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java
@@ -32,7 +32,7 @@ import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityDynamicType;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.sensor.feed.http.HttpFeed;
 import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
 import org.apache.brooklyn.util.collections.Jsonya;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNode.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNode.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNode.java
index 2dd9067..b668e1b 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNode.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNode.java
@@ -35,13 +35,13 @@ import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.config.MapConfigKey;
 import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.java.UsesJava;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.net.Networking;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java b/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java
index 2886257..64ef6ac 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java
@@ -28,8 +28,8 @@ import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.effector.AddSensor;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
-import org.apache.brooklyn.sensor.core.HttpRequestSensor;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
+import org.apache.brooklyn.core.sensor.HttpRequestSensor;
 import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;
 import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
 import org.apache.brooklyn.sensor.feed.jmx.JmxHelper;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/main/java/org/apache/brooklyn/entity/java/UsesJavaMXBeans.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/java/UsesJavaMXBeans.java b/software/base/src/main/java/org/apache/brooklyn/entity/java/UsesJavaMXBeans.java
index 4f2d20b..6922a76 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/java/UsesJavaMXBeans.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/java/UsesJavaMXBeans.java
@@ -23,8 +23,8 @@ import java.util.Map;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 public interface UsesJavaMXBeans {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/main/java/org/apache/brooklyn/entity/java/UsesJmx.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/java/UsesJmx.java b/software/base/src/main/java/org/apache/brooklyn/entity/java/UsesJmx.java
index dedbbd9..7d44bd3 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/java/UsesJmx.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/java/UsesJmx.java
@@ -28,9 +28,9 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.BasicConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.location.PortRanges;
-import org.apache.brooklyn.sensor.core.AttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 public interface UsesJmx extends UsesJava {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/main/java/org/apache/brooklyn/entity/java/VanillaJavaApp.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/java/VanillaJavaApp.java b/software/base/src/main/java/org/apache/brooklyn/entity/java/VanillaJavaApp.java
index 9319406..fe6f352 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/java/VanillaJavaApp.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/java/VanillaJavaApp.java
@@ -25,8 +25,8 @@ import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineAttributes.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineAttributes.java b/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineAttributes.java
index a9c2d22..1a7ac9b 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineAttributes.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineAttributes.java
@@ -24,7 +24,7 @@ import javax.annotation.Nullable;
 
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.config.render.RendererHints;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.util.guava.Functionals;
 import org.apache.brooklyn.util.math.MathFunctions;
 import org.apache.brooklyn.util.text.ByteSizeStrings;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/main/java/org/apache/brooklyn/entity/machine/pool/ServerPool.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/machine/pool/ServerPool.java b/software/base/src/main/java/org/apache/brooklyn/entity/machine/pool/ServerPool.java
index 3cf29e7..668a89e 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/machine/pool/ServerPool.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/machine/pool/ServerPool.java
@@ -37,9 +37,9 @@ import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.core.location.cloud.CloudLocationConfig;
 import org.apache.brooklyn.core.location.dynamic.LocationOwner;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.group.DynamicCluster;
 import org.apache.brooklyn.entity.machine.MachineEntity;
-import org.apache.brooklyn.sensor.core.Sensors;
 
 /**
  * A preallocated server pool is an entity that other applications can deploy to.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/main/java/org/apache/brooklyn/entity/machine/pool/ServerPoolImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/machine/pool/ServerPoolImpl.java b/software/base/src/main/java/org/apache/brooklyn/entity/machine/pool/ServerPoolImpl.java
index 4307ff6..c7696e4 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/machine/pool/ServerPoolImpl.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/machine/pool/ServerPoolImpl.java
@@ -41,11 +41,11 @@ import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.location.BasicLocationDefinition;
 import org.apache.brooklyn.core.location.Machines;
 import org.apache.brooklyn.core.location.dynamic.DynamicLocation;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.group.AbstractMembershipTrackingPolicy;
 import org.apache.brooklyn.entity.group.DynamicClusterImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
 import org.apache.brooklyn.util.guava.Maybe;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessWinRmDriver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessWinRmDriver.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessWinRmDriver.java
index 339b459..3965f4a 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessWinRmDriver.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessWinRmDriver.java
@@ -28,9 +28,9 @@ import java.util.concurrent.TimeUnit;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.python.core.PyException;
 import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.exceptions.ReferenceWithError;
 import org.apache.brooklyn.util.repeat.Repeater;
 import org.apache.brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractVanillaProcess.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractVanillaProcess.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractVanillaProcess.java
index ef9c9c4..35bdd94 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractVanillaProcess.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractVanillaProcess.java
@@ -20,7 +20,7 @@ package org.apache.brooklyn.entity.software.base;
 
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.sensor.core.AttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
 
 public interface AbstractVanillaProcess extends SoftwareProcess {
     AttributeSensorAndConfigKey<String, String> DOWNLOAD_URL = SoftwareProcess.DOWNLOAD_URL;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SameServerEntity.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SameServerEntity.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SameServerEntity.java
index 0a0af1d..ea82b3d 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SameServerEntity.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SameServerEntity.java
@@ -30,7 +30,7 @@ import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ComputeServiceIndicatorsFromChildrenAndMembers;
 import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.QuorumCheck;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcess.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcess.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcess.java
index 55ff5be..cee2d40 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcess.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcess.java
@@ -33,8 +33,8 @@ import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle.Transition;
 import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.sensor.core.AttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcessImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcessImpl.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcessImpl.java
index 3dabbc9..f2dc269 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcessImpl.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcessImpl.java
@@ -484,7 +484,7 @@ public abstract class SoftwareProcessImpl extends AbstractEntity implements Soft
 
     /** returns the ports that this entity wants to use;
      * default implementation returns {@link SoftwareProcess#REQUIRED_OPEN_LOGIN_PORTS} plus first value 
-     * for each {@link org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey} config key {@link PortRange}
+     * for each {@link org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey} config key {@link PortRange}
      * plus any ports defined with a config keys ending in {@code .port}.
      */
     protected Collection<Integer> getRequiredOpenPorts() {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaWindowsProcess.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaWindowsProcess.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaWindowsProcess.java
index 1354b03..6390eba 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaWindowsProcess.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaWindowsProcess.java
@@ -24,7 +24,7 @@ import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.util.time.Duration;
 
 import com.google.common.collect.ImmutableSet;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandSensor.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandSensor.java b/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandSensor.java
index c3dd177..59dc3c2 100644
--- a/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandSensor.java
+++ b/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandSensor.java
@@ -25,9 +25,9 @@ import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.effector.AddSensor;
+import org.apache.brooklyn.core.sensor.HttpRequestSensor;
 import org.apache.brooklyn.entity.java.JmxAttributeSensor;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.HttpRequestSensor;
 import org.apache.brooklyn.sensor.feed.ssh.SshFeed;
 import org.apache.brooklyn.sensor.feed.ssh.SshPollConfig;
 import org.apache.brooklyn.sensor.feed.ssh.SshValueFunctions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/main/java/org/apache/brooklyn/sensor/winrm/WindowsPerformanceCounterSensors.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/sensor/winrm/WindowsPerformanceCounterSensors.java b/software/base/src/main/java/org/apache/brooklyn/sensor/winrm/WindowsPerformanceCounterSensors.java
index d4415a9..ad02ce9 100644
--- a/software/base/src/main/java/org/apache/brooklyn/sensor/winrm/WindowsPerformanceCounterSensors.java
+++ b/software/base/src/main/java/org/apache/brooklyn/sensor/winrm/WindowsPerformanceCounterSensors.java
@@ -26,7 +26,7 @@ import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.sensor.feed.windows.WindowsPerformanceCounterFeed;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.text.Strings;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/MockBrooklynNode.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/MockBrooklynNode.java b/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/MockBrooklynNode.java
index 8e5b0bd..c07d899 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/MockBrooklynNode.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/MockBrooklynNode.java
@@ -25,12 +25,12 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
 import org.apache.brooklyn.entity.brooklynnode.EntityHttpClient;
 import org.apache.brooklyn.entity.brooklynnode.CallbackEntityHttpClient.Request;
 import org.apache.brooklyn.entity.brooklynnode.effector.SetHighAvailabilityModeEffectorBody;
 import org.apache.brooklyn.entity.brooklynnode.effector.SetHighAvailabilityPriorityEffectorBody;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
 
 import com.google.common.base.Function;
 import com.google.common.reflect.TypeToken;



[33/36] incubator-brooklyn git commit: Rename o.a.b.sensor.enricher to o.a.b.core.enricher

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/enricher/stock/SensorTransformingEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/SensorTransformingEnricher.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/SensorTransformingEnricher.java
new file mode 100644
index 0000000..92319f1
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/SensorTransformingEnricher.java
@@ -0,0 +1,106 @@
+/*
+ * 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.enricher.stock;
+
+import org.apache.brooklyn.api.entity.Entity;
+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.util.groovy.GroovyJavaMethods;
+import org.apache.brooklyn.util.javalang.JavaClassNames;
+import org.apache.brooklyn.util.time.Duration;
+
+import groovy.lang.Closure;
+
+import com.google.common.base.Function;
+
+/**
+ * @deprecated since 0.7.0; use {@link Enrichers.builder()}
+ * @see Transformer if need to sub-class
+ */
+public class SensorTransformingEnricher<T,U> extends AbstractTypeTransformingEnricher {
+
+    private Function<? super T, ? extends U> transformation;
+
+    public SensorTransformingEnricher(Entity producer, Sensor<T> source, Sensor<U> target, Function<? super T, ? extends U> transformation) {
+        super(producer, source, target);
+        this.transformation = transformation;
+        this.uniqueTag = JavaClassNames.simpleClassName(getClass())+":"+source.getName()+"*->"+target.getName();;
+    }
+
+    public SensorTransformingEnricher(Entity producer, Sensor<T> source, Sensor<U> target, Closure transformation) {
+        this(producer, source, target, GroovyJavaMethods.functionFromClosure(transformation));
+    }
+
+    public SensorTransformingEnricher(Sensor<T> source, Sensor<U> target, Function<T,U> transformation) {
+        this(null, source, target, transformation);
+    }
+
+    public SensorTransformingEnricher(Sensor<T> source, Sensor<U> target, Closure transformation) {
+        this(null, source, target, GroovyJavaMethods.functionFromClosure(transformation));
+    }
+
+    @Override
+    public void onEvent(SensorEvent event) {
+        if (accept((T)event.getValue())) {
+            if (target instanceof AttributeSensor)
+                entity.setAttribute((AttributeSensor)target, compute((T)event.getValue()));
+            else 
+                entity.emit(target, compute((T)event.getValue()));
+        }
+    }
+
+    protected boolean accept(T value) {
+        return true;
+    }
+
+    protected U compute(T value) {
+        return transformation.apply(value);
+    }
+
+    /** 
+     * creates an enricher which listens to a source (from the producer), 
+     * transforms it and publishes it under the target
+     * 
+     * Instead, consider calling:
+     * <pre>
+     * {@code
+     * addEnricher(Enrichers.builder()
+     *         .transforming(source)
+     *         .publishing(target)
+     *         .from(producer)
+     *         .computing(transformation)
+     *         .build());
+     * }
+     * </pre>
+     * 
+     * @deprecated since 0.7.0; use {@link Enrichers.builder()}
+     */
+    public static <U,V> SensorTransformingEnricher<U,V> newInstanceTransforming(Entity producer, AttributeSensor<U> source,
+            Function<U,V> transformation, AttributeSensor<V> target) {
+        return new SensorTransformingEnricher<U,V>(producer, source, target, transformation);
+    }
+
+    /** as {@link #newInstanceTransforming(Entity, AttributeSensor, Function, AttributeSensor)}
+     * using the same sensor as the source and the target */
+    public static <T> SensorTransformingEnricher<T,T> newInstanceTransforming(Entity producer, AttributeSensor<T> sensor,
+            Function<T,T> transformation) {
+        return newInstanceTransforming(producer, sensor, transformation, sensor);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/enricher/stock/Transformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/Transformer.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/Transformer.java
new file mode 100644
index 0000000..ef23ab4
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/Transformer.java
@@ -0,0 +1,103 @@
+/*
+ * 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.enricher.stock;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import org.apache.brooklyn.api.sensor.SensorEvent;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.util.collections.MutableSet;
+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.Function;
+import com.google.common.reflect.TypeToken;
+
+//@Catalog(name="Transformer", description="Transforms attributes of an entity; see Enrichers.builder().transforming(...)")
+@SuppressWarnings("serial")
+public class Transformer<T,U> extends AbstractTransformer<T,U> {
+
+    @SuppressWarnings("unused")
+    private static final Logger LOG = LoggerFactory.getLogger(Transformer.class);
+
+    // exactly one of these should be supplied to set a value
+    public static ConfigKey<?> TARGET_VALUE = ConfigKeys.newConfigKey(Object.class, "enricher.targetValue");
+    public static ConfigKey<Function<?, ?>> TRANSFORMATION_FROM_VALUE = ConfigKeys.newConfigKey(new TypeToken<Function<?, ?>>() {}, "enricher.transformation");
+    public static ConfigKey<Function<?, ?>> TRANSFORMATION_FROM_EVENT = ConfigKeys.newConfigKey(new TypeToken<Function<?, ?>>() {}, "enricher.transformation.fromevent");
+    
+    public Transformer() {
+    }
+
+    /** returns a function for transformation, for immediate use only (not for caching, as it may change) */
+    @Override
+    @SuppressWarnings("unchecked")
+    protected Function<SensorEvent<T>, U> getTransformation() {
+        MutableSet<Object> suppliers = MutableSet.of();
+        suppliers.addIfNotNull(config().getRaw(TARGET_VALUE).orNull());
+        suppliers.addIfNotNull(config().getRaw(TRANSFORMATION_FROM_EVENT).orNull());
+        suppliers.addIfNotNull(config().getRaw(TRANSFORMATION_FROM_VALUE).orNull());
+        checkArgument(suppliers.size()==1,  
+            "Must set exactly one of: %s, %s, %s", TARGET_VALUE.getName(), TRANSFORMATION_FROM_VALUE.getName(), TRANSFORMATION_FROM_EVENT.getName());
+        
+        Function<?, ?> fromEvent = config().get(TRANSFORMATION_FROM_EVENT);
+        if (fromEvent != null) {  
+            return (Function<SensorEvent<T>, U>) fromEvent;
+        }
+        
+        final Function<T, U> fromValueFn = (Function<T, U>) config().get(TRANSFORMATION_FROM_VALUE);
+        if (fromValueFn != null) {
+            // named class not necessary as result should not be serialized
+            return new Function<SensorEvent<T>, U>() {
+                @Override public U apply(SensorEvent<T> input) {
+                    return fromValueFn.apply(input.getValue());
+                }
+                @Override
+                public String toString() {
+                    return ""+fromValueFn;
+                }
+            };
+        }
+
+        // from target value
+        // named class not necessary as result should not be serialized
+        final Object targetValueRaw = config().getRaw(TARGET_VALUE).orNull();
+        return new Function<SensorEvent<T>, U>() {
+            @Override public U apply(SensorEvent<T> input) {
+                // evaluate immediately, or return null
+                // PRETTY_QUICK/200ms seems a reasonable compromise for tasks which require BG evaluation
+                // but which are non-blocking
+                // TODO better would be to have a mode in which tasks are not permitted to block on
+                // external events; they can submit tasks and block on them (or even better, have a callback architecture);
+                // however that is a non-trivial refactoring
+                return (U) Tasks.resolving(targetValueRaw).as(targetSensor.getType())
+                    .context(entity)
+                    .description("Computing sensor "+targetSensor+" from "+targetValueRaw)
+                    .timeout(ValueResolver.PRETTY_QUICK_WAIT)
+                    .getMaybe().orNull();
+            }
+            public String toString() {
+                return ""+targetValueRaw;
+            }
+        };
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/enricher/stock/UpdatingMap.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/UpdatingMap.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/UpdatingMap.java
new file mode 100644
index 0000000..b09b6d6
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/UpdatingMap.java
@@ -0,0 +1,159 @@
+/*
+ * 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.enricher.stock;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.api.sensor.SensorEvent;
+import org.apache.brooklyn.api.sensor.SensorEventListener;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.flags.SetFromFlag;
+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.collect.Maps;
+import com.google.common.reflect.TypeToken;
+
+/**
+ * Enricher which updates an entry in a sensor map ({@link #TARGET_SENSOR}) 
+ * based on the value of another sensor ({@link #SOURCE_SENSOR}.
+ * <p>
+ * The key used defaults to the name of the source sensor but can be specified with {@link #KEY_IN_TARGET_SENSOR}.
+ * The value placed in the map is the result of applying the function in {@link #COMPUTING} to the sensor value,
+ * with default behaviour being to remove an entry if <code>null</code> is returned
+ * but this can be overriden by setting {@link #REMOVING_IF_RESULT_IS_NULL} false.
+ * {@link Entities#REMOVE} and {@link Entities#UNCHANGED} are also respeced as return values for the computation
+ * (ignoring generics).
+ * Unlike most other enrichers, this defaults to {@link AbstractEnricher#SUPPRESS_DUPLICATES} being true
+ *  
+ * @author alex
+ *
+ * @param <S> source sensor type
+ * @param <TKey> key type in target sensor map
+ * @param <TVal> value type in target sensor map
+ */
+@SuppressWarnings("serial")
+public class UpdatingMap<S,TKey,TVal> extends AbstractEnricher implements SensorEventListener<S> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UpdatingMap.class);
+
+    @SetFromFlag("fromSensor")
+    public static final ConfigKey<Sensor<?>> SOURCE_SENSOR = ConfigKeys.newConfigKey(new TypeToken<Sensor<?>>() {}, "enricher.sourceSensor");
+    @SetFromFlag("targetSensor")
+    public static final ConfigKey<Sensor<?>> TARGET_SENSOR = ConfigKeys.newConfigKey(new TypeToken<Sensor<?>>() {}, "enricher.targetSensor");
+    @SetFromFlag("key")
+    public static final ConfigKey<?> KEY_IN_TARGET_SENSOR = ConfigKeys.newConfigKey(Object.class, "enricher.updatingMap.keyInTargetSensor",
+        "Key to update in the target sensor map, defaulting to the name of the source sensor");
+    @SetFromFlag("computing")
+    public static final ConfigKey<Function<?, ?>> COMPUTING = ConfigKeys.newConfigKey(new TypeToken<Function<?,?>>() {}, "enricher.updatingMap.computing");
+    @SetFromFlag("removingIfResultIsNull")
+    public static final ConfigKey<Boolean> REMOVING_IF_RESULT_IS_NULL = ConfigKeys.newBooleanConfigKey("enricher.updatingMap.removingIfResultIsNull", 
+        "Whether the key in the target map is removed if the result if the computation is null");
+
+    protected AttributeSensor<S> sourceSensor;
+    protected AttributeSensor<Map<TKey,TVal>> targetSensor;
+    protected TKey key;
+    protected Function<S,? extends TVal> computing;
+    protected Boolean removingIfResultIsNull;
+
+    public UpdatingMap() {
+        this(Maps.newLinkedHashMap());
+    }
+
+    public UpdatingMap(Map<Object, Object> flags) {
+        super(flags);
+        // this always suppresses duplicates, but it updates the same map *in place* so the usual suppress duplicates logic should not be applied
+        // TODO clean up so that we have synchronization guarantees and can inspect the item to see whether it has changed
+        suppressDuplicates = false;
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Override
+    public void setEntity(EntityLocal entity) {
+        super.setEntity(entity);
+        this.sourceSensor = (AttributeSensor<S>) getRequiredConfig(SOURCE_SENSOR);
+        this.targetSensor = (AttributeSensor<Map<TKey,TVal>>) getRequiredConfig(TARGET_SENSOR);
+        this.key = (TKey) getConfig(KEY_IN_TARGET_SENSOR);
+        this.computing = (Function) getRequiredConfig(COMPUTING);
+        this.removingIfResultIsNull = getConfig(REMOVING_IF_RESULT_IS_NULL);
+
+        subscribe(entity, sourceSensor, this);
+        onUpdated();
+    }
+    
+    @Override
+    public void onEvent(SensorEvent<S> event) {
+        onUpdated();
+    }
+
+    /**
+     * Called whenever the values for the set of producers changes (e.g. on an event, or on a member added/removed).
+     */
+    @SuppressWarnings("unchecked")
+    protected void onUpdated() {
+        try {
+            Object v = computing.apply(entity.getAttribute(sourceSensor));
+            if (v == null && !Boolean.FALSE.equals(removingIfResultIsNull)) {
+                v = Entities.REMOVE;
+            }
+            if (v == Entities.UNCHANGED) {
+                // nothing
+            } else {
+                // TODO check synchronization
+                TKey key = this.key;
+                if (key==null) key = (TKey) sourceSensor.getName();
+                
+                Map<TKey, TVal> map = entity.getAttribute(targetSensor);
+
+                boolean created = (map==null);
+                if (created) map = MutableMap.of();
+                
+                boolean changed;
+                if (v == Entities.REMOVE) {
+                    changed = map.containsKey(key);
+                    if (changed)
+                        map.remove(key);
+                } else {
+                    TVal oldV = map.get(key);
+                    if (oldV==null)
+                        changed = (v!=null || !map.containsKey(key));
+                    else
+                        changed = !oldV.equals(v);
+                    if (changed)
+                        map.put(key, (TVal)v);
+                }
+                if (changed || created)
+                    emit(targetSensor, map);
+            }
+        } catch (Throwable t) {
+            LOG.warn("Error calculating map update for enricher "+this, t);
+            throw Exceptions.propagate(t);
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/enricher/stock/YamlRollingTimeWindowMeanEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/YamlRollingTimeWindowMeanEnricher.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/YamlRollingTimeWindowMeanEnricher.java
new file mode 100644
index 0000000..f4e5484
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/YamlRollingTimeWindowMeanEnricher.java
@@ -0,0 +1,178 @@
+/*
+ * 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.enricher.stock;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.api.sensor.SensorEvent;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.util.time.Duration;
+
+import com.google.common.base.Function;
+
+/**
+ * Transforms {@link Sensor} data into a rolling average based on a time window.
+ * 
+ * All values within the window are weighted or discarded based on the timestamps associated with
+ * them (discards occur when a new value is added or an average is requested)
+ * <p>
+ * This will not extrapolate figures - it is assumed a value is valid and correct for the entire
+ * time period between it and the previous value. Normally, the average attribute is only updated
+ * when a new value arrives so it can give a fully informed average, but there is a danger of this
+ * going stale.
+ * <p>
+ * When an average is requested, it is likely there will be a segment of the window for which there
+ * isn't a value. Instead of extrapolating a value and providing different extrapolation techniques,
+ * the average is reported with a confidence value which reflects the fraction of the time
+ * window for which the values were valid.
+ * <p>
+ * Consumers of the average may ignore the confidence value and just use the last known average.
+ * They could multiply the returned value by the confidence value to get a decay-type behavior as
+ * the window empties. A third alternative is to, at a certain confidence threshold, report that
+ * the average is no longer meaningful.
+ * <p>
+ * The default average when no data has been received is 0, with a confidence of 0
+ */
+public class YamlRollingTimeWindowMeanEnricher<T extends Number> extends AbstractTransformer<T,Double> {
+    
+    public static ConfigKey<Duration> WINDOW_DURATION = ConfigKeys.newConfigKey(Duration.class, "enricher.window.duration",
+        "Duration for which this window should store data, default one minute", Duration.ONE_MINUTE);
+
+    public static ConfigKey<Double> CONFIDENCE_REQUIRED_TO_PUBLISH = ConfigKeys.newDoubleConfigKey("enricher.window.confidenceRequired",
+        "Minimum confidence level (ie period covered) required to publish a rolling average", 0.8d);
+
+    public static class ConfidenceQualifiedNumber {
+        final Double value;
+        final double confidence;
+        
+        public ConfidenceQualifiedNumber(Double value, double confidence) {
+            this.value = value;
+            this.confidence = confidence;
+        }
+        
+        @Override
+        public String toString() {
+            return ""+value+" ("+(int)(confidence*100)+"%)";
+        } 
+        
+    }
+    
+    private final LinkedList<T> values = new LinkedList<T>();
+    private final LinkedList<Long> timestamps = new LinkedList<Long>();
+    volatile ConfidenceQualifiedNumber lastAverage = new ConfidenceQualifiedNumber(0d,0d);
+    
+    @Override
+    protected Function<SensorEvent<T>, Double> getTransformation() {
+        return new Function<SensorEvent<T>, Double>() {
+            @Override
+            public Double apply(SensorEvent<T> event) {
+                long eventTime = event.getTimestamp();
+                if (event.getValue()==null) {
+                    return null;
+                }
+                values.addLast(event.getValue());
+                timestamps.addLast(eventTime);
+                if (eventTime>0) {
+                    ConfidenceQualifiedNumber average = getAverage(eventTime, 0);
+
+                    if (average.confidence > getConfig(CONFIDENCE_REQUIRED_TO_PUBLISH)) { 
+                        // without confidence, we might publish wildly varying estimates,
+                        // causing spurious resizes, so allow it to be configured, and
+                        // by default require a high value
+
+                        // TODO would be nice to include timestamp, etc
+                        return average.value; 
+                    }
+                }
+                return null;
+            }
+        };
+    }
+    
+    public ConfidenceQualifiedNumber getAverage(long fromTime, long graceAllowed) {
+        if (timestamps.isEmpty()) {
+            return lastAverage = new ConfidenceQualifiedNumber(lastAverage.value, 0.0d);
+        }
+        
+        long firstTimestamp = -1;
+        Iterator<Long> ti = timestamps.iterator();
+        while (ti.hasNext()) {
+            firstTimestamp = ti.next();
+            if (firstTimestamp>0) break;
+        }
+        if (firstTimestamp<=0) {
+            // no values with reasonable timestamps
+            return lastAverage = new ConfidenceQualifiedNumber(values.get(values.size()-1).doubleValue(), 0.0d);
+        }
+
+        long lastTimestamp = timestamps.get(timestamps.size()-1);
+
+        long now = fromTime;
+        if (lastTimestamp > fromTime - graceAllowed) {
+            // without this, if the computation takes place X seconds after the publish,
+            // we treat X seconds as time for which we have no confidence in the data
+            now = lastTimestamp;
+        }
+        pruneValues(now);
+        
+        Duration timePeriod = getConfig(WINDOW_DURATION);
+        long windowStart = Math.max(now-timePeriod.toMilliseconds(), firstTimestamp);
+        long windowEnd = Math.max(now-timePeriod.toMilliseconds(), lastTimestamp);
+        Double confidence = ((double)(windowEnd - windowStart)) / timePeriod.toMilliseconds();
+        if (confidence <= 0.0000001d) {
+            // not enough timestamps in window 
+            double lastValue = values.get(values.size()-1).doubleValue();
+            return lastAverage = new ConfidenceQualifiedNumber(lastValue, 0.0d);
+        }
+        
+        long start = windowStart;
+        long end;
+        double weightedAverage = 0.0d;
+        
+        Iterator<T> valuesIter = values.iterator();
+        Iterator<Long> timestampsIter = timestamps.iterator();
+        while (valuesIter.hasNext()) {
+            // Ignores null and out-of-date values (and also values that are received out-of-order, but that shouldn't happen!)
+            Number val = valuesIter.next();
+            Long timestamp = timestampsIter.next();
+            if (val!=null && timestamp >= start) {
+                end = timestamp;
+                weightedAverage += ((end - start) / (confidence * timePeriod.toMilliseconds())) * val.doubleValue();
+                start = timestamp;
+            }
+        }
+        
+        return lastAverage = new ConfidenceQualifiedNumber(weightedAverage, confidence);
+    }
+    
+    /**
+     * Discards out-of-date values, but keeps at least one value.
+     */
+    private void pruneValues(long now) {
+        // keep one value from before the period, so that we can tell the window's start time
+        Duration timePeriod = getConfig(WINDOW_DURATION);
+        while(timestamps.size() > 1 && timestamps.get(1) < (now - timePeriod.toMilliseconds())) {
+            timestamps.removeFirst();
+            values.removeFirst();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/enricher/stock/YamlTimeWeightedDeltaEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/YamlTimeWeightedDeltaEnricher.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/YamlTimeWeightedDeltaEnricher.java
new file mode 100644
index 0000000..e1a661e
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/YamlTimeWeightedDeltaEnricher.java
@@ -0,0 +1,83 @@
+/*
+ * 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.enricher.stock;
+
+import org.apache.brooklyn.api.sensor.SensorEvent;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.enricher.stock.AbstractTransformer;
+import org.apache.brooklyn.util.core.flags.TypeCoercions;
+import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Function;
+
+/**
+ * Converts an absolute count sensor into a delta sensor (i.e. the diff between the current and previous value),
+ * presented as a units/timeUnit based on the event timing.
+ * <p>
+ * For example, given a requests.count sensor, this can make a requests.per_sec sensor with {@link #DELTA_PERIOD} set to "1s" (the default).
+ * <p>
+ * Suitable for configuration from YAML.
+ */
+public class YamlTimeWeightedDeltaEnricher<T extends Number> extends AbstractTransformer<T,Double> {
+    private static final Logger LOG = LoggerFactory.getLogger(YamlTimeWeightedDeltaEnricher.class);
+    
+    transient Object lock = new Object();
+    Number lastValue;
+    long lastTime = -1;
+    
+    public static ConfigKey<Duration> DELTA_PERIOD = ConfigKeys.newConfigKey(Duration.class, "enricher.delta.period",
+        "Duration that this delta should compute for, default per second", Duration.ONE_SECOND);
+    
+    @Override
+    protected Function<SensorEvent<T>, Double> getTransformation() {
+        return new Function<SensorEvent<T>, Double>() {
+            @Override
+            public Double apply(SensorEvent<T> event) {
+                synchronized (lock) {
+                    Double current = TypeCoercions.coerce(event.getValue(), Double.class);
+
+                    if (current == null) return null;
+
+                    long eventTime = event.getTimestamp();
+                    long unitMillis = getConfig(DELTA_PERIOD).toMilliseconds();
+                    Double result = null;
+
+                    if (eventTime > 0 && eventTime > lastTime) {
+                        if (lastValue == null || lastTime < 0) {
+                            // cannot calculate time-based delta with a single value
+                            if (LOG.isTraceEnabled()) LOG.trace("{} received event but no last value so will not emit, null -> {} at {}", new Object[] {this, current, eventTime}); 
+                        } else {
+                            double duration = eventTime - lastTime;
+                            result = (current - lastValue.doubleValue()) / (duration / unitMillis);
+                        }
+                    }
+
+                    lastValue = current;
+                    lastTime = eventTime;
+
+                    return result;
+                }
+            }
+        };
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java
index daedc39..717b0e4 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java
@@ -41,7 +41,7 @@ import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.trait.Changeable;
 import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.groovy.GroovyJavaMethods;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/entity/stock/DelegateEntityImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/stock/DelegateEntityImpl.java b/core/src/main/java/org/apache/brooklyn/entity/stock/DelegateEntityImpl.java
index a160421..5728635 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/stock/DelegateEntityImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/stock/DelegateEntityImpl.java
@@ -20,7 +20,7 @@ package org.apache.brooklyn.entity.stock;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.core.entity.AbstractEntity;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 
 import com.google.common.base.Preconditions;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractAggregatingEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractAggregatingEnricher.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractAggregatingEnricher.java
deleted file mode 100644
index c140c9f..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractAggregatingEnricher.java
+++ /dev/null
@@ -1,173 +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.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.entity.Group;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.api.sensor.SensorEvent;
-import org.apache.brooklyn.api.sensor.SensorEventListener;
-import org.apache.brooklyn.core.entity.trait.Changeable;
-import org.apache.brooklyn.util.groovy.GroovyJavaMethods;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-import com.google.common.collect.ImmutableMap;
-
-
-/**
- * AggregatingEnrichers implicitly subscribes to the same sensor<S> on all entities inside an
- * {@link Group} and should emit an aggregate<T> on the target sensor
- * 
- * @deprecated since 0.7.0; use {@link Enrichers.builder()}
- * @see Aggregator if need to sub-class
- */
-public abstract class AbstractAggregatingEnricher<S,T> extends AbstractEnricher implements SensorEventListener<S> {
-    
-    private static final Logger LOG = LoggerFactory.getLogger(AbstractAggregatingEnricher.class);
-    
-    AttributeSensor<? extends S> source;
-    protected AttributeSensor<T> target;
-    protected S defaultValue;
-
-    Set<Entity> producers;
-    List<Entity> hardCodedProducers;
-    boolean allMembers;
-    Predicate<Entity> filter;
-    
-    /**
-     * 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<Entity, S> values = Collections.synchronizedMap(new LinkedHashMap<Entity, S>());
-
-    public AbstractAggregatingEnricher(Map<String,?> flags, AttributeSensor<? extends S> source, AttributeSensor<T> target) {
-        this(flags, source, target, null);
-    }
-    
-    @SuppressWarnings("unchecked")
-    public AbstractAggregatingEnricher(Map<String,?> flags, AttributeSensor<? extends S> source, AttributeSensor<T> target, S defaultValue) {
-        super(flags);
-        this.source = source;
-        this.target = target;
-        this.defaultValue = defaultValue;
-        hardCodedProducers = (List<Entity>) (flags.containsKey("producers") ? flags.get("producers") : Collections.emptyList());
-        allMembers = (Boolean) (flags.containsKey("allMembers") ? flags.get("allMembers") : false);
-        filter = flags.containsKey("filter") ? GroovyJavaMethods.<Entity>castToPredicate(flags.get("filter")) : Predicates.<Entity>alwaysTrue();
-    }
-
-    public void addProducer(Entity producer) {
-        if (LOG.isDebugEnabled()) LOG.debug("{} linked ({}, {}) to {}", new Object[] {this, producer, source, target});
-        subscribe(producer, source, this);
-        synchronized (values) {
-            S vo = values.get(producer);
-            if (vo==null) {
-                S initialVal = ((EntityLocal)producer).getAttribute(source);
-                values.put(producer, initialVal != null ? initialVal : defaultValue);
-                //we might skip in onEvent in the short window while !values.containsKey(producer)
-                //but that's okay because the put which would have been done there is done here now
-            } else {
-                //vo will be null unless some weird race with addProducer+removeProducer is occuring
-                //(and that's something we can tolerate i think)
-                if (LOG.isDebugEnabled()) LOG.debug("{} already had value ({}) for producer ({}); but that producer has just been added", new Object[] {this, vo, producer});
-            }
-        }
-        onUpdated();
-    }
-    
-    // TODO If producer removed but then get (queued) event from it after this method returns,  
-    public S removeProducer(Entity producer) {
-        if (LOG.isDebugEnabled()) LOG.debug("{} unlinked ({}, {}) from {}", new Object[] {this, producer, source, target});
-        unsubscribe(producer);
-        S removed = values.remove(producer);
-        onUpdated();
-        return removed;
-    }
-    
-    @Override
-    public void onEvent(SensorEvent<S> event) {
-        Entity e = event.getSource();
-        synchronized (values) {
-            if (values.containsKey(e)) {
-                values.put(e, event.getValue());
-            } else {
-                if (LOG.isDebugEnabled()) LOG.debug("{} received event for unknown producer ({}); presumably that producer has recently been removed", this, e);
-            }
-        }
-        onUpdated();
-    }
-
-    /**
-     * Called whenever the values for the set of producers changes (e.g. on an event, or on a member added/removed).
-     * Defaults to no-op
-     */
-    // TODO should this be abstract?
-    protected void onUpdated() {
-        // no-op
-    }
-    
-    @Override
-    public void setEntity(EntityLocal entity) {
-        super.setEntity(entity);
-        
-        for (Entity producer : hardCodedProducers) {
-            if (filter.apply(producer)) {
-                addProducer(producer);
-            }
-        }
-        
-        if (allMembers) {
-            subscribe(entity, Changeable.MEMBER_ADDED, new SensorEventListener<Entity>() {
-                @Override public void onEvent(SensorEvent<Entity> it) {
-                    if (filter.apply(it.getValue())) addProducer(it.getValue());
-                }
-            });
-            subscribe(entity, Changeable.MEMBER_REMOVED, new SensorEventListener<Entity>() {
-                @Override public void onEvent(SensorEvent<Entity> it) {
-                    removeProducer(it.getValue());
-                }
-            });
-            
-            if (entity instanceof Group) {
-                for (Entity member : ((Group)entity).getMembers()) {
-                    if (filter.apply(member)) {
-                        addProducer(member);
-                    }
-                }
-            }
-        }
-    }
-    
-    protected Map<Entity, S> copyOfValues() {
-        synchronized (values) {
-            return ImmutableMap.copyOf(values);
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractAggregator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractAggregator.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractAggregator.java
deleted file mode 100644
index a06e6d6..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractAggregator.java
+++ /dev/null
@@ -1,237 +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.Set;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.entity.Group;
-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.AbstractEntity;
-import org.apache.brooklyn.core.entity.trait.Changeable;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.guava.Maybe;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-import com.google.common.collect.Iterables;
-import com.google.common.reflect.TypeToken;
-
-/** Abstract superclass for enrichers which aggregate from children and/or members */
-@SuppressWarnings("serial")
-public abstract class AbstractAggregator<T,U> extends AbstractEnricher implements SensorEventListener<T> {
-
-    private static final Logger LOG = LoggerFactory.getLogger(AbstractAggregator.class);
-
-    public static final ConfigKey<Entity> PRODUCER = ConfigKeys.newConfigKey(Entity.class, "enricher.producer", "The entity whose children/members will be aggregated");
-
-    public static final ConfigKey<Sensor<?>> TARGET_SENSOR = ConfigKeys.newConfigKey(new TypeToken<Sensor<?>>() {}, "enricher.targetSensor");
-
-    // FIXME this is not just for "members" i think -Alex
-    public static final ConfigKey<?> DEFAULT_MEMBER_VALUE = ConfigKeys.newConfigKey(Object.class, "enricher.defaultMemberValue");
-
-    public static final ConfigKey<Set<? extends Entity>> FROM_HARDCODED_PRODUCERS = ConfigKeys.newConfigKey(new TypeToken<Set<? extends Entity>>() {}, "enricher.aggregating.fromHardcodedProducers");
-
-    public static final ConfigKey<Boolean> FROM_MEMBERS = ConfigKeys.newBooleanConfigKey("enricher.aggregating.fromMembers",
-        "Whether this enricher looks at members; only supported if a Group producer is supplier; defaults to true for Group entities");
-
-    public static final ConfigKey<Boolean> FROM_CHILDREN = ConfigKeys.newBooleanConfigKey("enricher.aggregating.fromChildren",
-        "Whether this enricher looks at children; this is the default for non-Group producers");
-
-    public static final ConfigKey<Predicate<? super Entity>> ENTITY_FILTER = ConfigKeys.newConfigKey(new TypeToken<Predicate<? super Entity>>() {}, "enricher.aggregating.entityFilter");
-
-    public static final ConfigKey<Predicate<?>> VALUE_FILTER = ConfigKeys.newConfigKey(new TypeToken<Predicate<?>>() {}, "enricher.aggregating.valueFilter");
-
-    protected Entity producer;
-    protected Sensor<U> targetSensor;
-    protected T defaultMemberValue;
-    protected Set<? extends Entity> fromHardcodedProducers;
-    protected Boolean fromMembers;
-    protected Boolean fromChildren;
-    protected Predicate<? super Entity> entityFilter;
-    protected Predicate<? super T> valueFilter;
-    
-    public AbstractAggregator() {}
-
-    @Override
-    public void setEntity(EntityLocal entity) {
-        super.setEntity(entity);
-        setEntityLoadingConfig();
-
-        if (fromHardcodedProducers == null && producer == null) producer = entity;
-        checkState(fromHardcodedProducers != null ^ producer != null, "must specify one of %s (%s) or %s (%s)", 
-                PRODUCER.getName(), producer, FROM_HARDCODED_PRODUCERS.getName(), fromHardcodedProducers);
-
-        if (fromHardcodedProducers != null) {
-            for (Entity producer : Iterables.filter(fromHardcodedProducers, entityFilter)) {
-                addProducerHardcoded(producer);
-            }
-        }
-        
-        if (isAggregatingMembers()) {
-            setEntityBeforeSubscribingProducerMemberEvents(entity);
-            setEntitySubscribeProducerMemberEvents();
-            setEntityAfterSubscribingProducerMemberEvents();
-        }
-        
-        if (isAggregatingChildren()) {
-            setEntityBeforeSubscribingProducerChildrenEvents();
-            setEntitySubscribingProducerChildrenEvents();
-            setEntityAfterSubscribingProducerChildrenEvents();
-        }
-        
-        onUpdated();
-    }
-
-    @SuppressWarnings({ "unchecked" })
-    protected void setEntityLoadingConfig() {
-        this.producer = getConfig(PRODUCER);
-        this.fromHardcodedProducers= getConfig(FROM_HARDCODED_PRODUCERS);
-        this.defaultMemberValue = (T) getConfig(DEFAULT_MEMBER_VALUE);
-        this.fromMembers = Maybe.fromNullable(getConfig(FROM_MEMBERS)).or(fromMembers);
-        this.fromChildren = Maybe.fromNullable(getConfig(FROM_CHILDREN)).or(fromChildren);
-        this.entityFilter = (Predicate<? super Entity>) (getConfig(ENTITY_FILTER) == null ? Predicates.alwaysTrue() : getConfig(ENTITY_FILTER));
-        this.valueFilter = (Predicate<? super T>) (getConfig(VALUE_FILTER) == null ? getDefaultValueFilter() : getConfig(VALUE_FILTER));
-        
-        setEntityLoadingTargetConfig();
-    }
-    
-    protected Predicate<?> getDefaultValueFilter() {
-        return Predicates.alwaysTrue();
-    }
-
-    @SuppressWarnings({ "unchecked" })
-    protected void setEntityLoadingTargetConfig() {
-        this.targetSensor = (Sensor<U>) getRequiredConfig(TARGET_SENSOR);
-    }
-
-    protected void setEntityBeforeSubscribingProducerMemberEvents(EntityLocal entity) {
-        checkState(producer instanceof Group, "Producer must be a group when fromMembers true: producer=%s; entity=%s; "
-                + "hardcodedProducers=%s", getConfig(PRODUCER), entity, fromHardcodedProducers);
-    }
-
-    protected void setEntitySubscribeProducerMemberEvents() {
-        subscribe(producer, Changeable.MEMBER_ADDED, new SensorEventListener<Entity>() {
-            @Override public void onEvent(SensorEvent<Entity> event) {
-                if (entityFilter.apply(event.getValue())) {
-                    addProducerMember(event.getValue());
-                    onUpdated();
-                }
-            }
-        });
-        subscribe(producer, Changeable.MEMBER_REMOVED, new SensorEventListener<Entity>() {
-            @Override public void onEvent(SensorEvent<Entity> event) {
-                removeProducer(event.getValue());
-                onUpdated();
-            }
-        });
-    }
-
-    protected void setEntityAfterSubscribingProducerMemberEvents() {
-        if (producer instanceof Group) {
-            for (Entity member : Iterables.filter(((Group)producer).getMembers(), entityFilter)) {
-                addProducerMember(member);
-            }
-        }
-    }
-
-    protected void setEntityBeforeSubscribingProducerChildrenEvents() {
-    }
-
-    protected void setEntitySubscribingProducerChildrenEvents() {
-        subscribe(producer, AbstractEntity.CHILD_REMOVED, new SensorEventListener<Entity>() {
-            @Override public void onEvent(SensorEvent<Entity> event) {
-                removeProducer(event.getValue());
-                onUpdated();
-            }
-        });
-        subscribe(producer, AbstractEntity.CHILD_ADDED, new SensorEventListener<Entity>() {
-            @Override public void onEvent(SensorEvent<Entity> event) {
-                if (entityFilter.apply(event.getValue())) {
-                    addProducerChild(event.getValue());
-                    onUpdated();
-                }
-            }
-        });
-    }
-
-    protected void setEntityAfterSubscribingProducerChildrenEvents() {
-        for (Entity child : Iterables.filter(producer.getChildren(), entityFilter)) {
-            addProducerChild(child);
-        }
-    }
-
-    /** true if this should aggregate members */
-    protected boolean isAggregatingMembers() {
-        if (Boolean.TRUE.equals(fromMembers)) return true;
-        if (Boolean.TRUE.equals(fromChildren)) return false;
-        if (fromHardcodedProducers!=null) return false;
-        if (producer instanceof Group) return true;
-        return false;
-    }
-    
-    /** true if this should aggregate members */
-    protected boolean isAggregatingChildren() {
-        if (Boolean.TRUE.equals(fromChildren)) return true;
-        if (Boolean.TRUE.equals(fromMembers)) return false;
-        if (fromHardcodedProducers!=null) return false;
-        if (producer instanceof Group) return false;
-        return true;
-    }
-    
-    protected abstract void addProducerHardcoded(Entity producer);
-    protected abstract void addProducerMember(Entity producer);
-    protected abstract void addProducerChild(Entity producer);
-    
-    // TODO If producer removed but then get (queued) event from it after this method returns,  
-    protected void removeProducer(Entity producer) {
-        if (LOG.isDebugEnabled()) LOG.debug("{} stopped listening to {}", new Object[] {this, producer });
-        unsubscribe(producer);
-        onProducerRemoved(producer);
-    }
-
-    protected abstract void onProducerAdded(Entity producer);
-
-    protected abstract void onProducerRemoved(Entity producer);
-
-
-    /**
-     * 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 aggregate for enricher "+this, t);
-            throw Exceptions.propagate(t);
-        }
-    }
-
-    protected abstract Object compute();
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractEnricher.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractEnricher.java
deleted file mode 100644
index edf407d..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractEnricher.java
+++ /dev/null
@@ -1,115 +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.Map;
-
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.mgmt.rebind.RebindSupport;
-import org.apache.brooklyn.api.mgmt.rebind.mementos.EnricherMemento;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.api.sensor.Enricher;
-import org.apache.brooklyn.api.sensor.EnricherType;
-import org.apache.brooklyn.api.sensor.Sensor;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.core.mgmt.rebind.BasicEnricherRebindSupport;
-import org.apache.brooklyn.core.objs.AbstractEntityAdjunct;
-import org.apache.brooklyn.util.core.flags.TypeCoercions;
-
-import com.google.common.base.Objects;
-import com.google.common.collect.Maps;
-
-/**
-* Base {@link Enricher} implementation; all enrichers should extend this or its children
-*/
-public abstract class AbstractEnricher extends AbstractEntityAdjunct implements Enricher {
-
-    public static final ConfigKey<Boolean> SUPPRESS_DUPLICATES = ConfigKeys.newBooleanConfigKey("enricher.suppressDuplicates",
-        "Whether duplicate values published by this enricher should be suppressed");
-
-    private final EnricherDynamicType enricherType;
-    protected Boolean suppressDuplicates;
-
-    public AbstractEnricher() {
-        this(Maps.newLinkedHashMap());
-    }
-    
-    public AbstractEnricher(Map<?,?> flags) {
-        super(flags);
-        
-        enricherType = new EnricherDynamicType(this);
-        
-        if (isLegacyConstruction() && !isLegacyNoConstructionInit()) {
-            init();
-        }
-    }
-
-    @Override
-    public RebindSupport<EnricherMemento> getRebindSupport() {
-        return new BasicEnricherRebindSupport(this);
-    }
-    
-    @Override
-    public EnricherType getEnricherType() {
-        return enricherType.getSnapshot();
-    }
-
-    @Override
-    public void setEntity(EntityLocal entity) {
-        super.setEntity(entity);
-        Boolean suppressDuplicates = getConfig(SUPPRESS_DUPLICATES);
-        if (suppressDuplicates!=null) 
-            this.suppressDuplicates = suppressDuplicates;
-    }
-    
-    @Override
-    protected void onChanged() {
-        requestPersist();
-    }
-
-    @Override
-    protected <T> void emit(Sensor<T> sensor, Object val) {
-        checkState(entity != null, "entity must first be set");
-        if (val == Entities.UNCHANGED) {
-            return;
-        }
-        if (val == Entities.REMOVE) {
-            ((EntityInternal)entity).removeAttribute((AttributeSensor<T>) sensor);
-            return;
-        }
-        
-        T newVal = TypeCoercions.coerce(val, sensor.getTypeToken());
-        if (sensor instanceof AttributeSensor) {
-            if (Boolean.TRUE.equals(suppressDuplicates)) {
-                T oldValue = entity.getAttribute((AttributeSensor<T>)sensor);
-                if (Objects.equal(oldValue, newVal))
-                    return;
-            }
-            entity.setAttribute((AttributeSensor<T>)sensor, newVal);
-        } else { 
-            entity.emit(sensor, newVal);
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractMultipleSensorAggregator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractMultipleSensorAggregator.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractMultipleSensorAggregator.java
deleted file mode 100644
index c625c90..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractMultipleSensorAggregator.java
+++ /dev/null
@@ -1,169 +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.Collections;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import org.apache.brooklyn.api.entity.Entity;
-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.core.BrooklynLogging;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.flags.TypeCoercions;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
-
-/** Building on {@link AbstractAggregator} for a single source sensor (on multiple children and/or members) */
-public abstract class AbstractMultipleSensorAggregator<U> extends AbstractAggregator<Object,U> implements SensorEventListener<Object> {
-
-    private static final Logger LOG = LoggerFactory.getLogger(AbstractMultipleSensorAggregator.class);
-
-    
-    /** access via {@link #getValues(Sensor)} */
-    private final Map<String, Map<Entity,Object>> values = Collections.synchronizedMap(new LinkedHashMap<String, Map<Entity,Object>>());
-
-    public AbstractMultipleSensorAggregator() {}
-
-    protected abstract Collection<Sensor<?>> getSourceSensors();
-    
-    @Override
-    protected void setEntityLoadingConfig() {
-        super.setEntityLoadingConfig();
-        Preconditions.checkNotNull(getSourceSensors(), "sourceSensors must be set");
-    }
-    
-    @Override
-    protected void setEntityBeforeSubscribingProducerChildrenEvents() {
-        BrooklynLogging.log(LOG, BrooklynLogging.levelDebugOrTraceIfReadOnly(producer),
-            "{} subscribing to children of {}", this, producer);
-        for (Sensor<?> sourceSensor: getSourceSensors()) {
-            subscribeToChildren(producer, sourceSensor, this);
-        }
-    }
-
-    @Override
-    protected void addProducerHardcoded(Entity producer) {
-        for (Sensor<?> sourceSensor: getSourceSensors()) {
-            subscribe(producer, sourceSensor, this);
-        }
-        onProducerAdded(producer);
-    }
-
-    @Override
-    protected void addProducerChild(Entity producer) {
-        // no `subscribe` call needed here, due to previous subscribeToChildren call
-        onProducerAdded(producer);
-    }
-
-    @Override
-    protected void addProducerMember(Entity producer) {
-        addProducerHardcoded(producer);
-    }
-
-    @Override
-    protected void onProducerAdded(Entity producer) {
-        BrooklynLogging.log(LOG, BrooklynLogging.levelDebugOrTraceIfReadOnly(producer),
-            "{} listening to {}", this, producer);
-        synchronized (values) {
-            for (Sensor<?> sensor: getSourceSensors()) {
-                Map<Entity,Object> vs = values.get(sensor.getName());
-                if (vs==null) {
-                    vs = new LinkedHashMap<Entity,Object>();
-                    values.put(sensor.getName(), vs);
-                }
-                
-                Object vo = vs.get(producer);
-                if (vo==null) {
-                    Object initialVal;
-                    if (sensor instanceof AttributeSensor) {
-                        initialVal = producer.getAttribute((AttributeSensor<?>)sensor);
-                    } else {
-                        initialVal = null;
-                    }
-                    vs.put(producer, initialVal != null ? initialVal : defaultMemberValue);
-                    // NB: see notes on possible race, in Aggregator#onProducerAdded
-                }
-                
-            }
-        }
-    }
-    
-    @Override
-    protected void onProducerRemoved(Entity producer) {
-        synchronized (values) {
-            for (Sensor<?> sensor: getSourceSensors()) {
-                Map<Entity,Object> vs = values.get(sensor.getName());
-                if (vs!=null)
-                    vs.remove(producer);
-            }
-        }
-        onUpdated();
-    }
-
-    @Override
-    public void onEvent(SensorEvent<Object> event) {
-        Entity e = event.getSource();
-        synchronized (values) {
-            Map<Entity,Object> vs = values.get(event.getSensor().getName());
-            if (vs==null) {
-                LOG.debug(this+" received event when no entry for sensor ("+event+"); likely just added or removed, and will initialize subsequently if needed");
-            } else {
-                vs.put(e, event.getValue());
-            }
-        }
-        onUpdated();
-    }
-
-    public <T> Map<Entity,T> getValues(Sensor<T> sensor) {
-        Map<Entity, T> valuesCopy = copyValues(sensor);
-        return coerceValues(valuesCopy, sensor.getType());
-    }
-
-    private <T> Map<Entity, T> coerceValues(Map<Entity, T> values, Class<? super T> type) {
-        Map<Entity, T> typedValues = MutableMap.of();
-        for (Entry<Entity, T> entry : values.entrySet()) {
-            @SuppressWarnings("unchecked")
-            T typedValue = (T) TypeCoercions.coerce(entry.getValue(), type);
-            typedValues.put(entry.getKey(), typedValue);
-        }
-        return typedValues;
-    }
-
-    private <T> Map<Entity, T> copyValues(Sensor<T> sensor) {
-        synchronized (values) {
-            @SuppressWarnings("unchecked")
-            Map<Entity, T> sv = (Map<Entity, T>) values.get(sensor.getName());
-            //use MutableMap because of potentially null values
-            return MutableMap.copyOf(sv).asUnmodifiable();
-        }
-    }
-    
-    @Override
-    protected abstract Object compute();
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractTransformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractTransformer.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractTransformer.java
deleted file mode 100644
index 1ff7938..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractTransformer.java
+++ /dev/null
@@ -1,100 +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.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.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Function;
-import com.google.common.reflect.TypeToken;
-
-@SuppressWarnings("serial")
-public abstract class AbstractTransformer<T,U> extends AbstractEnricher implements SensorEventListener<T> {
-
-    private static final Logger LOG = LoggerFactory.getLogger(AbstractTransformer.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");
-    
-    protected Entity producer;
-    protected Sensor<T> sourceSensor;
-    protected Sensor<U> targetSensor;
-
-    public AbstractTransformer() {
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Override
-    public void setEntity(EntityLocal entity) {
-        super.setEntity(entity);
-
-        Function<SensorEvent<T>, U> transformation = getTransformation();
-        this.producer = getConfig(PRODUCER) == null ? entity: getConfig(PRODUCER);
-        this.sourceSensor = (Sensor<T>) getRequiredConfig(SOURCE_SENSOR);
-        Sensor<?> targetSensorSpecified = getConfig(TARGET_SENSOR);
-        this.targetSensor = targetSensorSpecified!=null ? (Sensor<U>) targetSensorSpecified : (Sensor<U>) this.sourceSensor;
-        if (producer.equals(entity) && targetSensorSpecified==null) {
-            LOG.error("Refusing to add an enricher which reads and publishes on the same sensor: "+
-                producer+"."+sourceSensor+" (computing "+transformation+")");
-            // we don't throw because this error may manifest itself after a lengthy deployment, 
-            // and failing it at that point simply because of an enricher is not very pleasant
-            // (at least not until we have good re-run support across the board)
-            return;
-        }
-        
-        subscribe(producer, sourceSensor, this);
-        
-        if (sourceSensor instanceof AttributeSensor) {
-            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));
-            }
-        }
-    }
-
-    /** returns a function for transformation, for immediate use only (not for caching, as it may change) */
-    protected abstract Function<SensorEvent<T>, U> getTransformation();
-
-    @Override
-    public void onEvent(SensorEvent<T> event) {
-        emit(targetSensor, compute(event));
-    }
-
-    protected Object compute(SensorEvent<T> event) {
-        // transformation is not going to change, but this design makes it easier to support changing config in future. 
-        // if it's an efficiency hole we can switch to populate the transformation at start.
-        U result = getTransformation().apply(event);
-        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/AbstractTransformingEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractTransformingEnricher.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractTransformingEnricher.java
deleted file mode 100644
index 4fea37a..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractTransformingEnricher.java
+++ /dev/null
@@ -1,38 +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.entity.Entity;
-import org.apache.brooklyn.api.sensor.Sensor;
-
-/**
- * Convenience base for transforming a single sensor into a single new sensor of the same type
- * 
- * @deprecated since 0.7.0; use {@link Enrichers.builder()}
- */
-public abstract class AbstractTransformingEnricher<T> extends AbstractTypeTransformingEnricher<T,T> {
-
-    public AbstractTransformingEnricher() { // for rebinding
-    }
-    
-    public AbstractTransformingEnricher(Entity producer, Sensor<T> source, Sensor<T> target) {
-        super(producer, source, target);
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractTypeTransformingEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractTypeTransformingEnricher.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractTypeTransformingEnricher.java
deleted file mode 100644
index f66004c..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractTypeTransformingEnricher.java
+++ /dev/null
@@ -1,67 +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.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.SensorEventListener;
-import org.apache.brooklyn.core.sensor.BasicSensorEvent;
-import org.apache.brooklyn.util.core.flags.SetFromFlag;
-
-/**
- * Convenience base for transforming a single sensor into a single new sensor of the same type
- * 
- * @deprecated since 0.7.0; use {@link Enrichers.builder()}
- */
-public abstract class AbstractTypeTransformingEnricher<T,U> extends AbstractEnricher implements SensorEventListener<T> {
-    
-    @SetFromFlag
-    private Entity producer;
-    
-    @SetFromFlag
-    private Sensor<T> source;
-    
-    @SetFromFlag
-    protected Sensor<U> target;
-
-    public AbstractTypeTransformingEnricher() { // for rebind
-    }
-    
-    public AbstractTypeTransformingEnricher(Entity producer, Sensor<T> source, Sensor<U> target) {
-        this.producer = producer;
-        this.source = source;
-        this.target = target;
-    }
-    
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    public void setEntity(EntityLocal entity) {
-        super.setEntity(entity);
-        if (producer==null) producer = entity;
-        subscribe(producer, source, this);
-        
-        if (source instanceof AttributeSensor) {
-            Object value = producer.getAttribute((AttributeSensor)source);
-            // TODO Aled didn't you write a convenience to "subscribeAndRunIfSet" ? (-Alex)
-            if (value!=null)
-                onEvent(new BasicSensorEvent(source, producer, value, -1));
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/AddingEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/AddingEnricher.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/AddingEnricher.java
deleted file mode 100644
index 997f974..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/AddingEnricher.java
+++ /dev/null
@@ -1,106 +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.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.core.sensor.BasicSensorEvent;
-
-/** 
- * enricher which adds multiple sensors on an entity to produce a new sensor
- * 
- * Instead, consider calling:
- * <pre>
- * {@code
- * addEnricher(Enrichers.builder()
- *         .combining(sources)
- *         .publishing(target)
- *         .computeSum()
- *         .build());
- * }
- * </pre>
- * <p>
- * 
- * @deprecated since 0.7.0; use {@link Enrichers.builder()}
- * @see Combiner if need to sub-class
- */
-public class AddingEnricher extends AbstractEnricher implements SensorEventListener {
-
-    private Sensor[] sources;
-    private Sensor<? extends Number> target;
-
-    public AddingEnricher(Sensor sources[], Sensor<? extends Number> target) {
-        this.sources = sources;
-        this.target = target;
-    }
-
-    public void setEntity(EntityLocal entity) {
-        super.setEntity(entity);
-        
-        for (Sensor source: sources) {
-            subscribe(entity, source, this);
-            if (source instanceof AttributeSensor) {
-                Object value = entity.getAttribute((AttributeSensor)source);
-                if (value!=null)
-                    onEvent(new BasicSensorEvent(source, entity, value, -1));
-            }
-        }
-    }
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    @Override
-    public void onEvent(SensorEvent event) {
-        Number value = recompute();
-        Number typedValue = cast(value, (Class<? extends Number>)target.getType());
-        if (target instanceof AttributeSensor) {
-            entity.setAttribute((AttributeSensor)target, typedValue);
-        } else if (typedValue!=null)
-            entity.emit((Sensor)target, typedValue);
-    }
-
-    @SuppressWarnings("unchecked")
-    public static <V> V cast(Number value, Class<V> type) {
-        if (value==null) return null;
-        if (type.isInstance(value)) return (V)value;
-        
-        if (type==Integer.class) return (V) (Integer) (int)Math.round(value.doubleValue());
-        if (type==Long.class) return (V) (Long) Math.round(value.doubleValue());
-        if (type==Double.class) return (V) (Double) value.doubleValue();
-        if (type==Float.class) return (V) (Float) value.floatValue();
-        if (type==Byte.class) return (V) (Byte) (byte)Math.round(value.doubleValue());
-        if (type==Short.class) return (V) (Short) (short)Math.round(value.doubleValue());
-        
-        throw new UnsupportedOperationException("conversion of mathematical operation to "+type+" not supported");
-    }
-
-    protected Number recompute() {
-        if (sources.length==0) return null;
-        Double result = 0d;
-        for (Sensor source: sources) {
-            Object value = entity.getAttribute((AttributeSensor) source);
-            if (value==null) return null;
-            result += ((Number)value).doubleValue();
-        }
-        return result;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/Aggregator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Aggregator.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/Aggregator.java
deleted file mode 100644
index af828bc..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Aggregator.java
+++ /dev/null
@@ -1,221 +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.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
-import org.apache.brooklyn.api.entity.Entity;
-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.BrooklynLogging;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.util.collections.MutableList;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.flags.SetFromFlag;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.text.StringPredicates;
-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;
-
-/** Building on {@link AbstractAggregator} for a single source sensor (on multiple children and/or members) */
-@SuppressWarnings("serial")
-//@Catalog(name="Aggregator", description="Aggregates attributes from multiple entities into a single attribute value; see Enrichers.builder().aggregating(...)")
-public class Aggregator<T,U> extends AbstractAggregator<T,U> implements SensorEventListener<T> {
-
-    private static final Logger LOG = LoggerFactory.getLogger(Aggregator.class);
-
-    public static final ConfigKey<Sensor<?>> SOURCE_SENSOR = ConfigKeys.newConfigKey(new TypeToken<Sensor<?>>() {}, "enricher.sourceSensor");
-    
-    @SetFromFlag("transformation")
-    public static final ConfigKey<Object> TRANSFORMATION_UNTYPED = ConfigKeys.newConfigKey(Object.class, "enricher.transformation.untyped",
-        "Specifies a transformation, as a function from a collection to the value, or as a string matching a pre-defined named transformation, "
-        + "such as 'average' (for numbers), 'sum' (for numbers), or 'list' (the default, putting any collection of items into a list)");
-    public static final ConfigKey<Function<? super Collection<?>, ?>> TRANSFORMATION = ConfigKeys.newConfigKey(new TypeToken<Function<? super Collection<?>, ?>>() {}, "enricher.transformation");
-    
-    public static final ConfigKey<Boolean> EXCLUDE_BLANK = ConfigKeys.newBooleanConfigKey("enricher.aggregator.excludeBlank", "Whether explicit nulls or blank strings should be excluded (default false); this only applies if no value filter set", false);
-
-    protected Sensor<T> sourceSensor;
-    protected Function<? super Collection<T>, ? extends U> transformation;
-    
-    /**
-     * 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<Entity, T> values = Collections.synchronizedMap(new LinkedHashMap<Entity, T>());
-
-    public Aggregator() {}
-
-    @SuppressWarnings("unchecked")
-    protected void setEntityLoadingConfig() {
-        super.setEntityLoadingConfig();
-        this.sourceSensor = (Sensor<T>) getRequiredConfig(SOURCE_SENSOR);
-        
-        this.transformation = (Function<? super Collection<T>, ? extends U>) config().get(TRANSFORMATION);
-        
-        Object t1 = config().get(TRANSFORMATION_UNTYPED);
-        Function<? super Collection<?>, ?> t2 = null;
-        if (t1 instanceof String) {
-            t2 = lookupTransformation((String)t1);
-            if (t2==null) {
-                LOG.warn("Unknown transformation '"+t1+"' for "+this+"; will use default transformation");
-            }
-        }
-        
-        if (this.transformation==null) {
-            this.transformation = (Function<? super Collection<T>, ? extends U>) t2;
-        } else if (t1!=null && !Objects.equals(t2, this.transformation)) {
-            throw new IllegalStateException("Cannot supply both "+TRANSFORMATION_UNTYPED+" and "+TRANSFORMATION+" unless they are equal.");
-        }
-    }
-        
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    protected Function<? super Collection<?>, ?> lookupTransformation(String t1) {
-        if ("average".equalsIgnoreCase(t1)) return new Enrichers.ComputingAverage(null, null, targetSensor.getTypeToken());
-        if ("sum".equalsIgnoreCase(t1)) return new Enrichers.ComputingAverage(null, null, targetSensor.getTypeToken());
-        if ("list".equalsIgnoreCase(t1)) return new ComputingList();
-        return null;
-    }
-
-    private class ComputingList<TT> implements Function<Collection<TT>, List<TT>> {
-        @Override
-        public List<TT> apply(Collection<TT> input) {
-            if (input==null) return null;
-            return MutableList.copyOf(input).asUnmodifiable();
-        }
-        
-    }
-    
-    @Override
-    protected void setEntityBeforeSubscribingProducerChildrenEvents() {
-        BrooklynLogging.log(LOG, BrooklynLogging.levelDebugOrTraceIfReadOnly(producer),
-            "{} subscribing to children of {}", this, producer);
-        subscribeToChildren(producer, sourceSensor, this);
-    }
-
-    @Override
-    protected void addProducerHardcoded(Entity producer) {
-        subscribe(producer, sourceSensor, this);
-        onProducerAdded(producer);
-    }
-
-    @Override
-    protected void addProducerChild(Entity producer) {
-        // no subscription needed here, due to the subscribeToChildren call
-        onProducerAdded(producer);
-    }
-
-    @Override
-    protected void addProducerMember(Entity producer) {
-        subscribe(producer, sourceSensor, this);
-        onProducerAdded(producer);
-    }
-
-    @Override
-    protected void onProducerAdded(Entity producer) {
-        BrooklynLogging.log(LOG, BrooklynLogging.levelDebugOrTraceIfReadOnly(producer),
-            "{} listening to {}", this, producer);
-        synchronized (values) {
-            T vo = values.get(producer);
-            if (vo==null) {
-                T initialVal;
-                if (sourceSensor instanceof AttributeSensor) {
-                    initialVal = producer.getAttribute((AttributeSensor<T>)sourceSensor);
-                } else {
-                    initialVal = null;
-                }
-                values.put(producer, initialVal != null ? initialVal : defaultMemberValue);
-                //we might skip in onEvent in the short window while !values.containsKey(producer)
-                //but that's okay because the put which would have been done there is done here now
-            } else {
-                //vo will be null unless some weird race with addProducer+removeProducer is occuring
-                //(and that's something we can tolerate i think)
-                if (LOG.isDebugEnabled()) LOG.debug("{} already had value ({}) for producer ({}); but that producer has just been added", new Object[] {this, vo, producer});
-            }
-        }
-    }
-    
-    @Override
-    protected Predicate<?> getDefaultValueFilter() {
-        if (getConfig(EXCLUDE_BLANK))
-            return StringPredicates.isNonBlank();
-        else
-            return Predicates.alwaysTrue();
-    }
-    
-    @Override
-    protected void onProducerRemoved(Entity producer) {
-        values.remove(producer);
-        onUpdated();
-    }
-
-    @Override
-    public void onEvent(SensorEvent<T> event) {
-        Entity e = event.getSource();
-        synchronized (values) {
-            if (values.containsKey(e)) {
-                values.put(e, event.getValue());
-            } else {
-                if (LOG.isDebugEnabled()) LOG.debug("{} received event for unknown producer ({}); presumably that producer has recently been removed", this, e);
-            }
-        }
-        onUpdated();
-    }
-
-    protected void onUpdated() {
-        try {
-            emit(targetSensor, compute());
-        } catch (Throwable t) {
-            LOG.warn("Error calculating and setting aggregate for enricher "+this, t);
-            throw Exceptions.propagate(t);
-        }
-    }
-    
-    @Override
-    protected Object compute() {
-        synchronized (values) {
-            // TODO Could avoid copying when filter not needed
-            List<T> vs = MutableList.copyOf(Iterables.filter(values.values(), valueFilter));
-            if (transformation==null) return vs;
-            return transformation.apply(vs);
-        }
-    }
-    
-    protected Map<Entity, T> copyOfValues() {
-        // Don't use ImmutableMap, as can contain null values
-        synchronized (values) {
-            return Collections.unmodifiableMap(MutableMap.copyOf(values));
-        }
-    }
-
-}



[08/36] incubator-brooklyn git commit: Rename o.a.b.effector.core to o.a.b.core.effector

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/effector/ssh/SshEffectorTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/ssh/SshEffectorTasks.java b/core/src/main/java/org/apache/brooklyn/core/effector/ssh/SshEffectorTasks.java
new file mode 100644
index 0000000..37e582d
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/ssh/SshEffectorTasks.java
@@ -0,0 +1,335 @@
+/*
+ * 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.core.effector.ssh;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.config.StringConfigMap;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.config.ConfigUtils;
+import org.apache.brooklyn.core.effector.EffectorBody;
+import org.apache.brooklyn.core.effector.EffectorTasks;
+import org.apache.brooklyn.core.effector.EffectorTasks.EffectorTaskFactory;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.location.internal.LocationInternal;
+import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.core.internal.ssh.SshTool;
+import org.apache.brooklyn.util.core.task.Tasks;
+import org.apache.brooklyn.util.core.task.ssh.SshFetchTaskFactory;
+import org.apache.brooklyn.util.core.task.ssh.SshFetchTaskWrapper;
+import org.apache.brooklyn.util.core.task.ssh.SshPutTaskFactory;
+import org.apache.brooklyn.util.core.task.ssh.SshPutTaskWrapper;
+import org.apache.brooklyn.util.core.task.ssh.SshTasks;
+import org.apache.brooklyn.util.core.task.ssh.internal.AbstractSshExecTaskFactory;
+import org.apache.brooklyn.util.core.task.ssh.internal.PlainSshExecTaskFactory;
+import org.apache.brooklyn.util.core.task.system.ProcessTaskFactory;
+import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.util.ssh.BashCommands;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.common.collect.Maps;
+
+/**
+ * Conveniences for generating {@link Task} instances to perform SSH activities.
+ * <p>
+ * If the {@link SshMachineLocation machine} is not specified directly it
+ * will be inferred from the {@link Entity} context of either the {@link Effector}
+ * or the current {@link Task}.
+ * 
+ * @see SshTasks
+ * @since 0.6.0
+ */
+@Beta
+public class SshEffectorTasks {
+
+    private static final Logger log = LoggerFactory.getLogger(SshEffectorTasks.class);
+    
+    public static final ConfigKey<Boolean> IGNORE_ENTITY_SSH_FLAGS = ConfigKeys.newBooleanConfigKey("ignoreEntitySshFlags",
+        "Whether to ignore any ssh flags (behaviour constraints) set on the entity or location " +
+        "where this is running, using only flags explicitly specified", false);
+    
+    /**
+     * Like {@link EffectorBody} but providing conveniences when in an entity with a single machine location.
+     */
+    public abstract static class SshEffectorBody<T> extends EffectorBody<T> {
+        
+        /** convenience for accessing the machine */
+        public SshMachineLocation machine() {
+            return EffectorTasks.getSshMachine(entity());
+        }
+
+        /** convenience for generating an {@link PlainSshExecTaskFactory} which can be further customised if desired, and then (it must be explicitly) queued */
+        public ProcessTaskFactory<Integer> ssh(String ...commands) {
+            return new SshEffectorTaskFactory<Integer>(commands).machine(machine());
+        }
+    }
+
+    /** variant of {@link PlainSshExecTaskFactory} which fulfills the {@link EffectorTaskFactory} signature so can be used directly as an impl for an effector,
+     * also injects the machine automatically; can also be used outwith effector contexts, and machine is still injected if it is
+     * run from inside a task at an entity with a single SshMachineLocation */
+    public static class SshEffectorTaskFactory<RET> extends AbstractSshExecTaskFactory<SshEffectorTaskFactory<RET>,RET> implements EffectorTaskFactory<RET> {
+
+        public SshEffectorTaskFactory(String ...commands) {
+            super(commands);
+        }
+        public SshEffectorTaskFactory(SshMachineLocation machine, String ...commands) {
+            super(machine, commands);
+        }
+        @Override
+        public ProcessTaskWrapper<RET> newTask(Entity entity, Effector<RET> effector, ConfigBag parameters) {
+            markDirty();
+            if (summary==null) summary(effector.getName()+" (ssh)");
+            machine(EffectorTasks.getSshMachine(entity));
+            return newTask();
+        }
+        @Override
+        public synchronized ProcessTaskWrapper<RET> newTask() {
+            Entity entity = BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
+            if (machine==null) {
+                if (log.isDebugEnabled())
+                    log.debug("Using an ssh task not in an effector without any machine; will attempt to infer the machine: "+this);
+                if (entity!=null)
+                    machine(EffectorTasks.getSshMachine(entity));
+            }
+            applySshFlags(getConfig(), entity, getMachine());
+            return super.newTask();
+        }
+        
+        @Override
+        public <T2> SshEffectorTaskFactory<T2> returning(ScriptReturnType type) {
+            return (SshEffectorTaskFactory<T2>) super.<T2>returning(type);
+        }
+
+        @Override
+        public SshEffectorTaskFactory<Boolean> returningIsExitCodeZero() {
+            return (SshEffectorTaskFactory<Boolean>) super.returningIsExitCodeZero();
+        }
+
+        public SshEffectorTaskFactory<String> requiringZeroAndReturningStdout() {
+            return (SshEffectorTaskFactory<String>) super.requiringZeroAndReturningStdout();
+        }
+        
+        public <RET2> SshEffectorTaskFactory<RET2> returning(Function<ProcessTaskWrapper<?>, RET2> resultTransformation) {
+            return (SshEffectorTaskFactory<RET2>) super.returning(resultTransformation);
+        }
+    }
+    
+    public static class SshPutEffectorTaskFactory extends SshPutTaskFactory implements EffectorTaskFactory<Void> {
+        public SshPutEffectorTaskFactory(String remoteFile) {
+            super(remoteFile);
+        }
+        public SshPutEffectorTaskFactory(SshMachineLocation machine, String remoteFile) {
+            super(machine, remoteFile);
+        }
+        @Override
+        public SshPutTaskWrapper newTask(Entity entity, Effector<Void> effector, ConfigBag parameters) {
+            machine(EffectorTasks.getSshMachine(entity));
+            applySshFlags(getConfig(), entity, getMachine());
+            return super.newTask();
+        }
+        @Override
+        public SshPutTaskWrapper newTask() {
+            Entity entity = BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
+            if (machine==null) {
+                if (log.isDebugEnabled())
+                    log.debug("Using an ssh put task not in an effector without any machine; will attempt to infer the machine: "+this);
+                if (entity!=null) {
+                    machine(EffectorTasks.getSshMachine(entity));
+                }
+
+            }
+            applySshFlags(getConfig(), entity, getMachine());
+            return super.newTask();
+        }
+    }
+
+    public static class SshFetchEffectorTaskFactory extends SshFetchTaskFactory implements EffectorTaskFactory<String> {
+        public SshFetchEffectorTaskFactory(String remoteFile) {
+            super(remoteFile);
+        }
+        public SshFetchEffectorTaskFactory(SshMachineLocation machine, String remoteFile) {
+            super(machine, remoteFile);
+        }
+        @Override
+        public SshFetchTaskWrapper newTask(Entity entity, Effector<String> effector, ConfigBag parameters) {
+            machine(EffectorTasks.getSshMachine(entity));
+            applySshFlags(getConfig(), entity, getMachine());
+            return super.newTask();
+        }
+        @Override
+        public SshFetchTaskWrapper newTask() {
+            Entity entity = BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
+            if (machine==null) {
+                if (log.isDebugEnabled())
+                    log.debug("Using an ssh fetch task not in an effector without any machine; will attempt to infer the machine: "+this);
+                if (entity!=null)
+                    machine(EffectorTasks.getSshMachine(entity));
+            }
+            applySshFlags(getConfig(), entity, getMachine());
+            return super.newTask();
+        }
+    }
+
+    public static SshEffectorTaskFactory<Integer> ssh(String ...commands) {
+        return new SshEffectorTaskFactory<Integer>(commands);
+    }
+
+    public static SshEffectorTaskFactory<Integer> ssh(List<String> commands) {
+        return ssh(commands.toArray(new String[commands.size()]));
+    }
+
+    public static SshPutTaskFactory put(String remoteFile) {
+        return new SshPutEffectorTaskFactory(remoteFile);
+    }
+
+    public static SshFetchEffectorTaskFactory fetch(String remoteFile) {
+        return new SshFetchEffectorTaskFactory(remoteFile);
+    }
+
+    /** task which returns 0 if pid is running */
+    public static SshEffectorTaskFactory<Integer> codePidRunning(Integer pid) {
+        return ssh("ps -p "+pid).summary("PID "+pid+" is-running check (exit code)").allowingNonZeroExitCode();
+    }
+    
+    /** task which fails if the given PID is not running */
+    public static SshEffectorTaskFactory<?> requirePidRunning(Integer pid) {
+        return codePidRunning(pid).summary("PID "+pid+" is-running check (required)").requiringExitCodeZero("Process with PID "+pid+" is required to be running");
+    }
+
+    /** as {@link #codePidRunning(Integer)} but returning boolean */
+    public static SshEffectorTaskFactory<Boolean> isPidRunning(Integer pid) {
+        return codePidRunning(pid).summary("PID "+pid+" is-running check (boolean)").returning(new Function<ProcessTaskWrapper<?>, Boolean>() {
+            public Boolean apply(@Nullable ProcessTaskWrapper<?> input) { return Integer.valueOf(0).equals(input.getExitCode()); }
+        });
+    }
+
+
+    /** task which returns 0 if pid in the given file is running;
+     * method accepts wildcards so long as they match a single file on the remote end
+     * <p>
+     * returns 1 if no matching file, 
+     * 1 if matching file but no matching process,
+     * and 2 if 2+ matching files */
+    public static SshEffectorTaskFactory<Integer> codePidFromFileRunning(final String pidFile) {
+        return ssh(BashCommands.chain(
+                // this fails, but isn't an error
+                BashCommands.requireTest("-f "+pidFile, "The PID file "+pidFile+" does not exist."),
+                // this fails and logs an error picked up later
+                BashCommands.requireTest("`ls "+pidFile+" | wc -w` -eq 1", "ERROR: there are multiple matching PID files"),
+                // this fails and logs an error picked up later
+                BashCommands.require("cat "+pidFile, "ERROR: the PID file "+pidFile+" cannot be read (permissions?)."),
+                // finally check the process
+                "ps -p `cat "+pidFile+"`")).summary("PID file "+pidFile+" is-running check (exit code)")
+                .allowingNonZeroExitCode()
+                .addCompletionListener(new Function<ProcessTaskWrapper<?>,Void>() {
+                    public Void apply(ProcessTaskWrapper<?> input) {
+                        if (input.getStderr().contains("ERROR:"))
+                            throw new IllegalStateException("Invalid or inaccessible PID filespec: "+pidFile);
+                        return null;
+                    }
+                });
+    }
+    
+    /** task which fails if the pid in the given file is not running (or if there is no such PID file);
+     * method accepts wildcards so long as they match a single file on the remote end (fails if 0 or 2+ matching files) */
+    public static SshEffectorTaskFactory<?> requirePidFromFileRunning(String pidFile) {
+        return codePidFromFileRunning(pidFile)
+                .summary("PID file "+pidFile+" is-running check (required)")
+                .requiringExitCodeZero("Process with PID from file "+pidFile+" is required to be running");
+    }
+
+    /** as {@link #codePidFromFileRunning(String)} but returning boolean */
+    public static SshEffectorTaskFactory<Boolean> isPidFromFileRunning(String pidFile) {
+        return codePidFromFileRunning(pidFile).summary("PID file "+pidFile+" is-running check (boolean)").
+                returning(new Function<ProcessTaskWrapper<?>, Boolean>() {
+                    public Boolean apply(@Nullable ProcessTaskWrapper<?> input) { return ((Integer)0).equals(input.getExitCode()); }
+                });
+    }
+
+    /** extracts the values for the main brooklyn.ssh.config.* config keys (i.e. those declared in ConfigKeys) 
+     * as declared on the entity, and inserts them in a map using the unprefixed state, for ssh.
+     * <p>
+     * currently this is computed for each call, which may be wasteful, but it is reliable in the face of config changes.
+     * we could cache the Map.  note that we do _not_ cache (or even own) the SshTool; 
+     * the SshTool is created or re-used by the SshMachineLocation making use of these properties */
+    @Beta
+    public static Map<String, Object> getSshFlags(Entity entity, Location optionalLocation) {
+        ConfigBag allConfig = ConfigBag.newInstance();
+        
+        StringConfigMap globalConfig = ((EntityInternal)entity).getManagementContext().getConfig();
+        allConfig.putAll(globalConfig.getAllConfig());
+        
+        if (optionalLocation!=null)
+            allConfig.putAll(((LocationInternal)optionalLocation).config().getBag());
+        
+        allConfig.putAll(((EntityInternal)entity).getAllConfig());
+        
+        Map<String, Object> result = Maps.newLinkedHashMap();
+        for (String keyS : allConfig.getAllConfig().keySet()) {
+            if (keyS.startsWith(SshTool.BROOKLYN_CONFIG_KEY_PREFIX)) {
+                ConfigKey<?> key = ConfigKeys.newConfigKey(Object.class, keyS);
+                
+                Object val = allConfig.getStringKey(keyS);
+                
+                /*
+                 * NOV 2013 changing this to rely on config above being inserted in the right order,
+                 * so entity config will be preferred over location, and location over global.
+                 * If that is consistent then remove the lines below.
+                 * (We can also accept null entity and so combine with SshTasks.getSshFlags.)
+                 */
+                
+//                // have to use raw config to test whether the config is set
+//                Object val = ((EntityInternal)entity).getConfigMap().getRawConfig(key);
+//                if (val!=null) {
+//                    val = entity.getConfig(key);
+//                } else {
+//                    val = globalConfig.getRawConfig(key);
+//                    if (val!=null) val = globalConfig.getConfig(key);
+//                }
+//                if (val!=null) {
+                    result.put(ConfigUtils.unprefixedKey(SshTool.BROOKLYN_CONFIG_KEY_PREFIX, key).getName(), val);
+//                }
+            }
+        }
+        return result;
+    }
+
+    private static void applySshFlags(ConfigBag config, Entity entity, Location machine) {
+        if (entity!=null) {
+            if (!config.get(IGNORE_ENTITY_SSH_FLAGS)) {
+                config.putIfAbsent(getSshFlags(entity, machine));
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java b/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java
index e35205a..ca561e1 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java
@@ -62,6 +62,7 @@ import org.apache.brooklyn.api.sensor.Sensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.config.ConfigKey.HasConfigKey;
 import org.apache.brooklyn.core.config.Sanitizer;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.entity.trait.StartableMethods;
 import org.apache.brooklyn.core.internal.BrooklynProperties;
@@ -76,7 +77,6 @@ import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.mgmt.internal.NonDeploymentManagementContext;
 import org.apache.brooklyn.core.objs.BrooklynObjectInternal;
 import org.apache.brooklyn.core.objs.proxy.EntityProxyImpl;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.sensor.core.DependentConfiguration;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.ResourceUtils;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/entity/EntityDynamicType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntityDynamicType.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntityDynamicType.java
index 0db0d46..6d65f41 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/EntityDynamicType.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntityDynamicType.java
@@ -31,14 +31,14 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntityType;
 import org.apache.brooklyn.api.sensor.Sensor;
 import org.apache.brooklyn.config.ConfigKey.HasConfigKey;
+import org.apache.brooklyn.core.effector.EffectorAndBody;
+import org.apache.brooklyn.core.effector.EffectorBody;
+import org.apache.brooklyn.core.effector.EffectorWithBody;
+import org.apache.brooklyn.core.effector.Effectors;
+import org.apache.brooklyn.core.effector.MethodEffector;
+import org.apache.brooklyn.core.effector.EffectorTasks.EffectorBodyTaskFactory;
+import org.apache.brooklyn.core.effector.EffectorTasks.EffectorTaskFactory;
 import org.apache.brooklyn.core.objs.BrooklynDynamicType;
-import org.apache.brooklyn.effector.core.EffectorAndBody;
-import org.apache.brooklyn.effector.core.EffectorBody;
-import org.apache.brooklyn.effector.core.EffectorWithBody;
-import org.apache.brooklyn.effector.core.Effectors;
-import org.apache.brooklyn.effector.core.MethodEffector;
-import org.apache.brooklyn.effector.core.EffectorTasks.EffectorBodyTaskFactory;
-import org.apache.brooklyn.effector.core.EffectorTasks.EffectorTaskFactory;
 import org.apache.brooklyn.util.javalang.Reflections;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/entity/trait/MemberReplaceable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/trait/MemberReplaceable.java b/core/src/main/java/org/apache/brooklyn/core/entity/trait/MemberReplaceable.java
index a67b1af..238e261 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/trait/MemberReplaceable.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/trait/MemberReplaceable.java
@@ -22,7 +22,7 @@ import java.util.NoSuchElementException;
 
 import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.annotation.EffectorParam;
-import org.apache.brooklyn.effector.core.MethodEffector;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.entity.group.StopFailedRuntimeException;
 
 public interface MemberReplaceable {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/entity/trait/Resizable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/trait/Resizable.java b/core/src/main/java/org/apache/brooklyn/core/entity/trait/Resizable.java
index ebf37d0..68c9398 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/trait/Resizable.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/trait/Resizable.java
@@ -21,7 +21,7 @@ package org.apache.brooklyn.core.entity.trait;
 
 import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.annotation.EffectorParam;
-import org.apache.brooklyn.effector.core.MethodEffector;
+import org.apache.brooklyn.core.effector.MethodEffector;
 
 /**
  * Defines an entity group that can be re-sized dynamically.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/entity/trait/Startable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/trait/Startable.java b/core/src/main/java/org/apache/brooklyn/core/entity/trait/Startable.java
index 304dba2..96812ce 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/trait/Startable.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/trait/Startable.java
@@ -26,10 +26,10 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.annotation.EffectorParam;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.EffectorBody;
+import org.apache.brooklyn.core.effector.Effectors;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.core.entity.Attributes;
-import org.apache.brooklyn.effector.core.EffectorBody;
-import org.apache.brooklyn.effector.core.Effectors;
-import org.apache.brooklyn.effector.core.MethodEffector;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.task.Tasks;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/entity/trait/StartableMethods.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/trait/StartableMethods.java b/core/src/main/java/org/apache/brooklyn/core/entity/trait/StartableMethods.java
index 47d1623..b49d259 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/trait/StartableMethods.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/trait/StartableMethods.java
@@ -26,9 +26,9 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.mgmt.TaskAdaptable;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityPredicates;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.task.DynamicTasks;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
index 4a018e3..49e1c1c 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
@@ -36,13 +36,13 @@ import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityFunctions;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.plan.PlanNotRecognizedException;
 import org.apache.brooklyn.core.plan.PlanToSpecFactory;
 import org.apache.brooklyn.core.plan.PlanToSpecTransformer;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.task.TaskBuilder;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EffectorUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EffectorUtils.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EffectorUtils.java
index 9429836..fa7eaaa 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EffectorUtils.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EffectorUtils.java
@@ -33,9 +33,9 @@ import org.apache.brooklyn.api.effector.Effector;
 import org.apache.brooklyn.api.effector.ParameterType;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.effector.BasicParameterType;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.effector.core.BasicParameterType;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.config.ConfigBag;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalManagementContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalManagementContext.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalManagementContext.java
index 24392e6..f464d3b 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalManagementContext.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalManagementContext.java
@@ -43,6 +43,7 @@ import org.apache.brooklyn.api.mgmt.SubscriptionManager;
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.api.mgmt.TaskAdaptable;
 import org.apache.brooklyn.core.BrooklynFeatureEnablement;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.drivers.downloads.BasicDownloadsManager;
 import org.apache.brooklyn.core.internal.BrooklynProperties;
 import org.apache.brooklyn.core.internal.BrooklynProperties.Factory.Builder;
@@ -52,7 +53,6 @@ import org.apache.brooklyn.core.mgmt.ha.OsgiManager;
 import org.apache.brooklyn.core.objs.proxy.InternalEntityFactory;
 import org.apache.brooklyn.core.objs.proxy.InternalLocationFactory;
 import org.apache.brooklyn.core.objs.proxy.InternalPolicyFactory;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.util.core.task.BasicExecutionContext;
 import org.apache.brooklyn.util.core.task.BasicExecutionManager;
 import org.apache.brooklyn.util.core.task.DynamicTasks;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java
index eb07bc1..e1d704b 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java
@@ -44,6 +44,10 @@ import org.apache.brooklyn.api.sensor.Feed;
 import org.apache.brooklyn.core.catalog.internal.CatalogBundleDto;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.config.BasicConfigKey;
+import org.apache.brooklyn.core.effector.BasicParameterType;
+import org.apache.brooklyn.core.effector.EffectorAndBody;
+import org.apache.brooklyn.core.effector.EffectorTasks.EffectorBodyTaskFactory;
+import org.apache.brooklyn.core.effector.EffectorTasks.EffectorTaskFactory;
 import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
 import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContextSequential;
 import org.apache.brooklyn.core.mgmt.classloading.ClassLoaderFromBrooklynClassLoadingContext;
@@ -55,10 +59,6 @@ import org.apache.brooklyn.core.mgmt.rebind.dto.BasicFeedMemento;
 import org.apache.brooklyn.core.mgmt.rebind.dto.BasicLocationMemento;
 import org.apache.brooklyn.core.mgmt.rebind.dto.BasicPolicyMemento;
 import org.apache.brooklyn.core.mgmt.rebind.dto.MutableBrooklynMemento;
-import org.apache.brooklyn.effector.core.BasicParameterType;
-import org.apache.brooklyn.effector.core.EffectorAndBody;
-import org.apache.brooklyn.effector.core.EffectorTasks.EffectorBodyTaskFactory;
-import org.apache.brooklyn.effector.core.EffectorTasks.EffectorTaskFactory;
 import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
 import org.apache.brooklyn.util.core.xstream.XmlSerializer;
 import org.apache.brooklyn.util.exceptions.Exceptions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/EntityProxyImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/EntityProxyImpl.java b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/EntityProxyImpl.java
index 3b6e52a..97b8f39 100644
--- a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/EntityProxyImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/EntityProxyImpl.java
@@ -33,6 +33,7 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.mgmt.TaskAdaptable;
+import org.apache.brooklyn.core.effector.EffectorWithBody;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.internal.EntityTransientCopyInternal;
@@ -41,7 +42,6 @@ import org.apache.brooklyn.core.mgmt.internal.EffectorUtils;
 import org.apache.brooklyn.core.mgmt.internal.EntityManagerInternal;
 import org.apache.brooklyn.core.mgmt.internal.ManagementTransitionMode;
 import org.apache.brooklyn.core.mgmt.rebind.RebindManagerImpl.RebindTracker;
-import org.apache.brooklyn.effector.core.EffectorWithBody;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
 import org.apache.brooklyn.util.core.task.TaskTags;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/effector/core/AbstractEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/effector/core/AbstractEffector.java b/core/src/main/java/org/apache/brooklyn/effector/core/AbstractEffector.java
deleted file mode 100644
index 74863c8..0000000
--- a/core/src/main/java/org/apache/brooklyn/effector/core/AbstractEffector.java
+++ /dev/null
@@ -1,90 +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.effector.core;
-
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Callable;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.api.effector.ParameterType;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.mgmt.Task;
-import org.apache.brooklyn.core.mgmt.internal.EffectorUtils;
-import org.apache.brooklyn.effector.core.EffectorTasks.EffectorTaskFactory;
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.core.task.DynamicSequentialTask;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.ImmutableMap;
-
-/**
- * The abstract {@link Effector} implementation.
- * 
- * The concrete subclass (often anonymous) will supply the {@link #call(Entity, Map)} implementation,
- * and the fields in the constructor.
- */
-public abstract class AbstractEffector<T> extends EffectorBase<T> implements EffectorWithBody<T> {
-
-    private static final long serialVersionUID = 1832435915652457843L;
-    
-    @SuppressWarnings("unused")
-    private static final Logger LOG = LoggerFactory.getLogger(AbstractEffector.class);
-
-    public AbstractEffector(String name, Class<T> returnType, List<ParameterType<?>> parameters, String description) {
-        super(name, returnType, parameters, description);
-    }
-
-    public abstract T call(Entity entity, @SuppressWarnings("rawtypes") Map parameters);
-
-    /** Convenience for named-parameter syntax (needs map in first argument) */
-    public T call(Entity entity) { return call(ImmutableMap.of(), entity); }
-
-    /** Convenience for named-parameter syntax (needs map in first argument) */
-    public T call(@SuppressWarnings("rawtypes") Map parameters, Entity entity) { return call(entity, parameters); }
-
-    /** @deprecated since 0.7.0 use {@link #getFlagsForTaskInvocationAt(Entity, Effector, ConfigBag)} */ @Deprecated
-    protected final Map<Object,Object> getFlagsForTaskInvocationAt(Entity entity) {
-        return getFlagsForTaskInvocationAt(entity, this, null);
-    }
-    /** subclasses may override to add additional flags, but they should include the flags returned here 
-     * unless there is very good reason not to */
-    protected Map<Object,Object> getFlagsForTaskInvocationAt(Entity entity, Effector<T> effector, ConfigBag parameters) {
-        return EffectorUtils.getTaskFlagsForEffectorInvocation(entity, effector, parameters);
-    }
-    
-    /** not meant for overriding; subclasses should override the abstract {@link #call(Entity, Map)} method in this class */
-    @Override
-    public final EffectorTaskFactory<T> getBody() {
-        return new EffectorTaskFactory<T>() {
-            @Override
-            public Task<T> newTask(final Entity entity, final Effector<T> effector, final ConfigBag parameters) {
-                return new DynamicSequentialTask<T>(
-                        getFlagsForTaskInvocationAt(entity, AbstractEffector.this, parameters),
-                        new Callable<T>() {
-                            @Override public T call() {
-                                return AbstractEffector.this.call(parameters.getAllConfig(), entity);
-                            }
-                        });
-            }
-        };
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/effector/core/AddChildrenEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/effector/core/AddChildrenEffector.java b/core/src/main/java/org/apache/brooklyn/effector/core/AddChildrenEffector.java
deleted file mode 100644
index 8a96e37..0000000
--- a/core/src/main/java/org/apache/brooklyn/effector/core/AddChildrenEffector.java
+++ /dev/null
@@ -1,117 +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.effector.core;
-
-import java.util.List;
-import java.util.Map;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.mgmt.EntityManagementUtils;
-import org.apache.brooklyn.core.mgmt.EntityManagementUtils.CreationResult;
-import org.apache.brooklyn.effector.core.Effectors.EffectorBuilder;
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.annotations.Beta;
-import com.google.gson.Gson;
-
-/** Entity initializer which defines an effector which adds a child blueprint to an entity.
- * <p>
- * One of the config keys {@link #BLUEPRINT_YAML} (containing a YAML blueprint (map or string)) 
- * or {@link #BLUEPRINT_TYPE} (containing a string referring to a catalog type) should be supplied, but not both.
- * Parameters defined here are supplied as config during the entity creation.
- * 
- * @since 0.7.0 */
-@Beta
-public class AddChildrenEffector extends AddEffector {
-    
-    private static final Logger log = LoggerFactory.getLogger(AddChildrenEffector.class);
-    
-    public static final ConfigKey<Object> BLUEPRINT_YAML = ConfigKeys.newConfigKey(Object.class, "blueprint_yaml");
-    public static final ConfigKey<String> BLUEPRINT_TYPE = ConfigKeys.newStringConfigKey("blueprint_type");
-    public static final ConfigKey<Boolean> AUTO_START = ConfigKeys.newBooleanConfigKey("auto_start");
-    
-    public AddChildrenEffector(ConfigBag params) {
-        super(newEffectorBuilder(params).build());
-    }
-    
-    public AddChildrenEffector(Map<String,String> params) {
-        this(ConfigBag.newInstance(params));
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    public static EffectorBuilder<List<String>> newEffectorBuilder(ConfigBag params) {
-        EffectorBuilder<List<String>> eff = (EffectorBuilder) AddEffector.newEffectorBuilder(List.class, params);
-        eff.impl(new Body(eff.buildAbstract(), params));
-        return eff;
-    }
-
-    protected static class Body extends EffectorBody<List<String>> {
-
-        private final Effector<?> effector;
-        private final String blueprintBase;
-        private final Boolean autostart;
-
-        public Body(Effector<?> eff, ConfigBag params) {
-            this.effector = eff;
-            String newBlueprint = null;
-            Object yaml = params.get(BLUEPRINT_YAML);
-            if (yaml instanceof Map) {
-                newBlueprint = new Gson().toJson(yaml);
-            } else if (yaml instanceof String) {
-                newBlueprint = (String) yaml;
-            } else if (yaml!=null) {
-                throw new IllegalArgumentException(this+" requires map or string in "+BLUEPRINT_YAML+"; not "+yaml.getClass()+" ("+yaml+")");
-            }
-            String blueprintType = params.get(BLUEPRINT_TYPE);
-            if (blueprintType!=null) {
-                if (newBlueprint!=null) {
-                    throw new IllegalArgumentException(this+" cannot take both "+BLUEPRINT_TYPE+" and "+BLUEPRINT_YAML);
-                }
-                newBlueprint = "services: [ { type: "+blueprintType+" } ]";
-            }
-            if (newBlueprint==null) {
-                throw new IllegalArgumentException(this+" requires either "+BLUEPRINT_TYPE+" or "+BLUEPRINT_YAML);
-            }
-            blueprintBase = newBlueprint;
-            autostart = params.get(AUTO_START);
-        }
-
-        @Override
-        public List<String> call(ConfigBag params) {
-            params = getMergedParams(effector, params);
-            
-            String blueprint = blueprintBase;
-            if (!params.isEmpty()) { 
-                blueprint = blueprint+"\n"+"brooklyn.config: "+
-                    new Gson().toJson(params.getAllConfig());
-            }
-
-            log.debug(this+" adding children to "+entity()+":\n"+blueprint);
-            CreationResult<List<Entity>, List<String>> result = EntityManagementUtils.addChildren(entity(), blueprint, autostart);
-            log.debug(this+" added children to "+entity()+": "+result.get());
-            return result.task().getUnchecked();
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/effector/core/AddEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/effector/core/AddEffector.java b/core/src/main/java/org/apache/brooklyn/effector/core/AddEffector.java
deleted file mode 100644
index 44f1d04..0000000
--- a/core/src/main/java/org/apache/brooklyn/effector/core/AddEffector.java
+++ /dev/null
@@ -1,116 +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.effector.core;
-
-import java.util.Collections;
-import java.util.Map;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.api.effector.ParameterType;
-import org.apache.brooklyn.api.entity.EntityInitializer;
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.config.MapConfigKey;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.effector.core.Effectors.EffectorBuilder;
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.text.Strings;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Preconditions;
-
-/** 
- * Entity initializer which adds an effector to an entity.
- * <p>
- * This instance provides a {@link #newEffectorBuilder(Class, ConfigBag)} 
- * which returns an abstract (body-less) effector defining:
- * <li> the name from {@link #EFFECTOR_NAME};
- * <li> the description from {@link #EFFECTOR_DESCRIPTION}
- * <li> the parameters from {@link #EFFECTOR_PARAMETER_DEFS}
- * <p>
- * Callers should pass the effector to instantiate into the constructor.
- * Often subclasses will supply a constructor which takes a ConfigBag of parameters,
- * and a custom {@link #newEffectorBuilder(Class, ConfigBag)} which adds the body
- * before passing to this class.
- * <p>
- * Note that the parameters passed to the call method in the body of the effector implementation
- * are only those supplied by a user at runtime; in order to merge with default
- * values, use {@link #getMergedParams(Effector, ConfigBag)}.
- *  
- * @since 0.7.0 */
-@Beta
-public class AddEffector implements EntityInitializer {
-    
-    public static final ConfigKey<String> EFFECTOR_NAME = ConfigKeys.newStringConfigKey("name");
-    public static final ConfigKey<String> EFFECTOR_DESCRIPTION = ConfigKeys.newStringConfigKey("description");
-    
-    public static final ConfigKey<Map<String,Object>> EFFECTOR_PARAMETER_DEFS = new MapConfigKey<Object>(Object.class, "parameters");
-
-    final Effector<?> effector;
-    
-    public AddEffector(Effector<?> effector) {
-        this.effector = Preconditions.checkNotNull(effector, "effector");
-    }
-    
-    @Override
-    public void apply(EntityLocal entity) {
-        ((EntityInternal)entity).getMutableEntityType().addEffector(effector);
-    }
-    
-    public static <T> EffectorBuilder<T> newEffectorBuilder(Class<T> type, ConfigBag params) {
-        String name = Preconditions.checkNotNull(params.get(EFFECTOR_NAME), "name must be supplied when defining an effector: %s", params);
-        EffectorBuilder<T> eff = Effectors.effector(type, name);
-        eff.description(params.get(EFFECTOR_DESCRIPTION));
-        
-        Map<String, Object> paramDefs = params.get(EFFECTOR_PARAMETER_DEFS);
-        if (paramDefs!=null) {
-            for (Map.Entry<String, Object> paramDef: paramDefs.entrySet()){
-                if (paramDef!=null) {
-                    String paramName = paramDef.getKey();
-                    Object value = paramDef.getValue();
-                    if (value==null) value = Collections.emptyMap();
-                    if (!(value instanceof Map)) {
-                        if (value instanceof CharSequence && Strings.isBlank((CharSequence) value)) 
-                            value = Collections.emptyMap();
-                    }
-                    if (!(value instanceof Map))
-                        throw new IllegalArgumentException("Illegal argument of type "+value.getClass()+" value '"+value+"' supplied as parameter definition "
-                            + "'"+paramName);
-                    eff.parameter(ConfigKeys.DynamicKeys.newNamedInstance(paramName, (Map<?, ?>) value));
-                }
-            }
-        }
-        
-        return eff;
-    }
-
-    /** returns a ConfigBag containing the merger of the supplied parameters with default values on the effector-defined parameters */
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    public static ConfigBag getMergedParams(Effector<?> eff, ConfigBag params) {
-        ConfigBag result = ConfigBag.newInstanceCopying(params);
-        for (ParameterType<?> param: eff.getParameters()) {
-            ConfigKey key = Effectors.asConfigKey(param);
-            if (!result.containsKey(key))
-                result.configure(key, params.get(key));
-        }
-        return result;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/effector/core/AddSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/effector/core/AddSensor.java b/core/src/main/java/org/apache/brooklyn/effector/core/AddSensor.java
deleted file mode 100644
index 84c2239..0000000
--- a/core/src/main/java/org/apache/brooklyn/effector/core/AddSensor.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.effector.core;
-
-import java.util.Map;
-
-import org.apache.brooklyn.api.entity.EntityInitializer;
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.sensor.core.Sensors;
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.guava.Maybe;
-import org.apache.brooklyn.util.javalang.Boxing;
-import org.apache.brooklyn.util.time.Duration;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Preconditions;
-
-/**
- * Creates a new {@link AttributeSensor} on an entity.
- * <p>
- * The configuration can include the sensor {@code name}, {@code period} and {@code targetType}.
- * For the targetType, currently this only supports classes on the initial classpath, not those in
- * OSGi bundles added at runtime.
- *
- * @since 0.7.0
- */
-@Beta
-public class AddSensor<T> implements EntityInitializer {
-
-    public static final ConfigKey<String> SENSOR_NAME = ConfigKeys.newStringConfigKey("name", "The name of the sensor to create");
-    public static final ConfigKey<Duration> SENSOR_PERIOD = ConfigKeys.newConfigKey(Duration.class, "period", "Period, including units e.g. 1m or 5s or 200ms; default 5 minutes", Duration.FIVE_MINUTES);
-    public static final ConfigKey<String> SENSOR_TYPE = ConfigKeys.newStringConfigKey("targetType", "Target type for the value; default String", "java.lang.String");
-
-    protected final String name;
-    protected final Duration period;
-    protected final String type;
-    protected final AttributeSensor<T> sensor;
-
-    public AddSensor(Map<String, String> params) {
-        this(ConfigBag.newInstance(params));
-    }
-
-    public AddSensor(final ConfigBag params) {
-        this.name = Preconditions.checkNotNull(params.get(SENSOR_NAME), "Name must be supplied when defining a sensor");
-        this.period = params.get(SENSOR_PERIOD);
-        this.type = params.get(SENSOR_TYPE);
-        this.sensor = newSensor();
-    }
-
-    @Override
-    public void apply(EntityLocal entity) {
-        ((EntityInternal) entity).getMutableEntityType().addSensor(sensor);
-    }
-
-    private AttributeSensor<T> newSensor() {
-        String className = getFullClassName(type);
-        Class<T> clazz = getType(className);
-        return Sensors.newSensor(clazz, name);
-    }
-
-    @SuppressWarnings("unchecked")
-    protected Class<T> getType(String className) {
-        try {
-            // TODO use OSGi loader (low priority however); also ensure that allows primitives
-            Maybe<Class<?>> primitive = Boxing.getPrimitiveType(className);
-            if (primitive.isPresent()) return (Class<T>) primitive.get();
-            return (Class<T>) Class.forName(className);
-        } catch (ClassNotFoundException e) {
-            if (!className.contains(".")) {
-                // could be assuming "java.lang" package; try again with that
-                try {
-                    return (Class<T>) Class.forName("java.lang."+className);
-                } catch (ClassNotFoundException e2) {
-                    throw new IllegalArgumentException("Invalid target type for sensor "+name+": " + className+" (also tried java.lang."+className+")");
-                }
-            } else {
-                throw new IllegalArgumentException("Invalid target type for sensor "+name+": " + className);
-            }
-        }
-    }
-
-    protected String getFullClassName(String className) {
-        if (className.equalsIgnoreCase("string")) {
-            return "java.lang.String";
-        } else if (className.equalsIgnoreCase("int") || className.equalsIgnoreCase("integer")) {
-            return "java.lang.Integer";
-        } else if (className.equalsIgnoreCase("long")) {
-            return "java.lang.Long";
-        } else if (className.equalsIgnoreCase("float")) {
-            return "java.lang.Float";
-        } else if (className.equalsIgnoreCase("double")) {
-            return "java.lang.Double";
-        } else if (className.equalsIgnoreCase("bool") || className.equalsIgnoreCase("boolean")) {
-            return "java.lang.Boolean";
-        } else if (className.equalsIgnoreCase("byte")) {
-            return "java.lang.Byte";
-        } else if (className.equalsIgnoreCase("char") || className.equalsIgnoreCase("character")) {
-            return "java.lang.Character";
-        } else if (className.equalsIgnoreCase("object")) {
-            return "java.lang.Object";
-        } else {
-            return className;
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/effector/core/BasicParameterType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/effector/core/BasicParameterType.java b/core/src/main/java/org/apache/brooklyn/effector/core/BasicParameterType.java
deleted file mode 100644
index 2367cd0..0000000
--- a/core/src/main/java/org/apache/brooklyn/effector/core/BasicParameterType.java
+++ /dev/null
@@ -1,116 +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.effector.core;
-
-import java.util.Collections;
-import java.util.Map;
-
-import org.apache.brooklyn.api.effector.ParameterType;
-
-import com.google.common.base.Objects;
-
-public class BasicParameterType<T> implements ParameterType<T> {
-    private static final long serialVersionUID = -5521879180483663919L;
-    
-    private String name;
-    private Class<T> type;
-    private String description;
-    private Boolean hasDefaultValue = null;
-    private T defaultValue = null;
-
-    public BasicParameterType() {
-        this(Collections.emptyMap());
-    }
-    
-    @SuppressWarnings("unchecked")
-    public BasicParameterType(Map<?, ?> arguments) {
-        if (arguments.containsKey("name")) name = (String) arguments.get("name");
-        if (arguments.containsKey("type")) type = (Class<T>) arguments.get("type");
-        if (arguments.containsKey("description")) description = (String) arguments.get("description");
-        if (arguments.containsKey("defaultValue")) defaultValue = (T) arguments.get("defaultValue");
-    }
-
-    public BasicParameterType(String name, Class<T> type) {
-        this(name, type, null, null, false);
-    }
-    
-    public BasicParameterType(String name, Class<T> type, String description) {
-        this(name, type, description, null, false);
-    }
-    
-    public BasicParameterType(String name, Class<T> type, String description, T defaultValue) {
-        this(name, type, description, defaultValue, true);
-    }
-    
-    public BasicParameterType(String name, Class<T> type, String description, T defaultValue, boolean hasDefaultValue) {
-        this.name = name;
-        this.type = type;
-        this.description = description;
-        this.defaultValue = defaultValue;
-        if (defaultValue!=null && !defaultValue.getClass().equals(Object.class)) {
-            // if default value is null (or is an Object, which is ambiguous on resolution to to rebind), 
-            // don't bother to set this as it creates noise in the persistence files
-            this.hasDefaultValue = hasDefaultValue;
-        }
-    }
-
-    @Override
-    public String getName() { return name; }
-
-    @Override
-    public Class<T> getParameterClass() { return type; }
-    
-    @Override
-    public String getParameterClassName() { return type.getCanonicalName(); }
-
-    @Override
-    public String getDescription() { return description; }
-
-    @Override
-    public T getDefaultValue() {
-        return hasDefaultValue() ? defaultValue : null;
-    }
-
-    public boolean hasDefaultValue() {
-        // a new Object() was previously used to indicate no default value, but that doesn't work well across serialization boundaries!
-        return hasDefaultValue!=null ? hasDefaultValue : defaultValue!=null && !defaultValue.getClass().equals(Object.class);
-    }
-    
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues()
-                .add("name", name).add("description", description).add("type", getParameterClassName())
-                .add("defaultValue", defaultValue)
-                .toString();
-    }
-    
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(name, description, type, defaultValue);
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        return (obj instanceof ParameterType) &&
-                Objects.equal(name, ((ParameterType<?>)obj).getName()) &&
-                Objects.equal(description, ((ParameterType<?>)obj).getDescription()) &&
-                Objects.equal(type, ((ParameterType<?>)obj).getParameterClass()) &&
-                Objects.equal(defaultValue, ((ParameterType<?>)obj).getDefaultValue());
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/effector/core/EffectorAndBody.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/effector/core/EffectorAndBody.java b/core/src/main/java/org/apache/brooklyn/effector/core/EffectorAndBody.java
deleted file mode 100644
index 71fbadb..0000000
--- a/core/src/main/java/org/apache/brooklyn/effector/core/EffectorAndBody.java
+++ /dev/null
@@ -1,60 +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.effector.core;
-
-import java.util.List;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.api.effector.ParameterType;
-import org.apache.brooklyn.effector.core.EffectorTasks.EffectorTaskFactory;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Objects;
-
-@Beta // added in 0.6.0
-public class EffectorAndBody<T> extends EffectorBase<T> implements EffectorWithBody<T> {
-
-    private static final long serialVersionUID = -6023389678748222968L;
-    private final EffectorTaskFactory<T> body;
-
-    public EffectorAndBody(Effector<T> original, EffectorTaskFactory<T> body) {
-        this(original.getName(), original.getReturnType(), original.getParameters(), original.getDescription(), body);
-    }
-    
-    public EffectorAndBody(String name, Class<T> returnType, List<ParameterType<?>> parameters, String description, EffectorTaskFactory<T> body) {
-        super(name, returnType, parameters, description);
-        this.body = body;
-    }
-
-    @Override
-    public EffectorTaskFactory<T> getBody() {
-        return body;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(super.hashCode(), getBody());
-    }
-    
-    @Override
-    public boolean equals(Object other) {
-        return super.equals(other) && Objects.equal(getBody(), ((EffectorAndBody<?>)other).getBody());
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/effector/core/EffectorBase.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/effector/core/EffectorBase.java b/core/src/main/java/org/apache/brooklyn/effector/core/EffectorBase.java
deleted file mode 100644
index 511b50b..0000000
--- a/core/src/main/java/org/apache/brooklyn/effector/core/EffectorBase.java
+++ /dev/null
@@ -1,106 +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.effector.core;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.api.effector.ParameterType;
-import org.apache.brooklyn.effector.core.EffectorTasks.EffectorTaskFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Joiner;
-import com.google.common.base.Objects;
-
-/** concrete implementation of Effector interface, 
- * but not (at this level of the hirarchy) defining an implementation 
- * (see {@link EffectorTaskFactory} and {@link EffectorWithBody}) */
-public class EffectorBase<T> implements Effector<T> {
-
-    @SuppressWarnings("unused")
-    private static final Logger log = LoggerFactory.getLogger(EffectorBase.class);
-    
-    private static final long serialVersionUID = -4153962199078384835L;
-    
-    private final String name;
-    private final Class<T> returnType;
-    private final List<ParameterType<?>> parameters;
-    private final String description;
-
-    public EffectorBase(String name, Class<T> returnType, List<ParameterType<?>> parameters, String description) {
-        this.name = name;
-        this.returnType = returnType;
-        this.parameters = new ArrayList<ParameterType<?>>(parameters);
-        this.description = description;
-    }
-
-    @Override
-    public String getName() {
-        return name;
-    }
-
-    @Override
-    public Class<T> getReturnType() {
-        return returnType;
-    }
-
-    @Override
-    public String getReturnTypeName() {
-        return returnType.getCanonicalName();
-    }
-
-    @Override
-    public List<ParameterType<?>> getParameters() {
-        return parameters;
-    }
-
-    @Override
-    public String getDescription() {
-        return description;
-    }
-
-    @Override
-    public String toString() {
-        List<String> parameterNames = new ArrayList<String>(parameters.size());
-        for (ParameterType<?> parameter: parameters) {
-            String parameterName = (parameter.getName() != null) ? parameter.getName() : "<unknown>";
-            parameterNames.add(parameterName);
-        }
-        return name+"["+Joiner.on(",").join(parameterNames)+"]";
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(name, returnType, parameters, description);
-    }
-    
-    @Override
-    public boolean equals(Object other) {
-        if (!(other instanceof EffectorBase)) return false;
-        if (!(other.getClass().equals(getClass()))) return false;
-        if (!Objects.equal(hashCode(), other.hashCode())) return false;
-        return Objects.equal(getName(), ((EffectorBase<?>)other).getName()) &&
-            Objects.equal(getReturnType(), ((EffectorBase<?>)other).getReturnType()) &&
-            Objects.equal(getParameters(), ((EffectorBase<?>)other).getParameters()) &&
-            Objects.equal(getDescription(), ((EffectorBase<?>)other).getDescription());
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/effector/core/EffectorBody.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/effector/core/EffectorBody.java b/core/src/main/java/org/apache/brooklyn/effector/core/EffectorBody.java
deleted file mode 100644
index 099bc71..0000000
--- a/core/src/main/java/org/apache/brooklyn/effector/core/EffectorBody.java
+++ /dev/null
@@ -1,100 +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.effector.core;
-
-import org.apache.brooklyn.api.mgmt.Task;
-import org.apache.brooklyn.api.mgmt.TaskAdaptable;
-import org.apache.brooklyn.api.mgmt.TaskFactory;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.core.flags.TypeCoercions;
-import org.apache.brooklyn.util.core.task.DynamicSequentialTask;
-import org.apache.brooklyn.util.core.task.DynamicTasks;
-import org.apache.brooklyn.util.core.task.Tasks;
-
-import com.google.common.annotations.Beta;
-
-/** Typical implementations override {@link #main(ConfigBag)} to do the work of the effector
- * <p>
- * See also {@link EffectorTasks}: possibly this will be deleted in preference for an approach based on {@link EffectorTasks}. 
- * 
- * @since 0.6.0
- **/
-@Beta
-public abstract class EffectorBody<T> {
-    /** Does the work of the effector, either in place, or (better) by building up
-     * subtasks, which can by added using {@link DynamicTasks} methods
-     * (and various convenience methods which do that automatically; see subclasses of EffectorBody 
-     * for more info on usage; or see {@link DynamicSequentialTask} for details of the threading model
-     * by which added tasks are placed in a secondary thread)
-     * <p>
-     * The associated entity can be accessed through the {@link #entity()} method.
-     */
-    public abstract T call(ConfigBag parameters);
-    
-    // NB: we could also support an 'init' method which is done at creation,
-    // as a place where implementers can describe the structure of the task before it executes
-    // (and init gets invoked in EffectorBodyTaskFactory.newTask _before_ the task is submitted and main is called)
-    
-    
-    // ---- convenience method(s) for implementers of main -- see subclasses and *Tasks statics for more
-    
-    protected EntityInternal entity() {
-        return (EntityInternal) BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
-    }
-    
-    protected <V extends TaskAdaptable<?>> V queue(V task) {
-        return DynamicTasks.queue(task);
-    }
-
-    protected <V extends TaskAdaptable<?>> void queue(V task1, V task2, V ...tasks) {
-        DynamicTasks.queue(task1);
-        DynamicTasks.queue(task2);
-        for (V task: tasks)
-            DynamicTasks.queue(task);
-    }
-
-    protected <V extends TaskFactory<?>> void queue(V task1, V task2, V ...tasks) {
-        DynamicTasks.queue(task1.newTask());
-        DynamicTasks.queue(task2.newTask());
-        for (V task: tasks)
-            DynamicTasks.queue(task.newTask());
-    }
-    
-    protected <U extends TaskAdaptable<?>> U queue(TaskFactory<U> task) {
-        return DynamicTasks.queue(task.newTask());
-    }
-    
-    /** see {@link DynamicTasks#waitForLast()} */
-    protected Task<?> waitForLast() {
-        return DynamicTasks.waitForLast();
-    }
-
-    /** Returns the result of the last task queued in this context, coerced to the given type */
-    protected <V> V last(Class<V> type) {
-        Task<?> last = waitForLast();
-        if (last==null)
-            throw new IllegalStateException("No last task available (in "+DynamicTasks.getTaskQueuingContext()+")");
-        if (!Tasks.isQueuedOrSubmitted(last))
-            throw new IllegalStateException("Last task "+last+" has not been queued or submitted; will not block on its result");
-        
-        return TypeCoercions.coerce(last.getUnchecked(), type);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/effector/core/EffectorTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/effector/core/EffectorTasks.java b/core/src/main/java/org/apache/brooklyn/effector/core/EffectorTasks.java
deleted file mode 100644
index 249da53..0000000
--- a/core/src/main/java/org/apache/brooklyn/effector/core/EffectorTasks.java
+++ /dev/null
@@ -1,229 +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.effector.core;
-
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.api.effector.ParameterType;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.mgmt.Task;
-import org.apache.brooklyn.api.mgmt.TaskAdaptable;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.location.Machines;
-import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.core.mgmt.internal.EffectorUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.core.task.DynamicSequentialTask;
-import org.apache.brooklyn.util.core.task.DynamicTasks;
-import org.apache.brooklyn.util.core.task.TaskBuilder;
-import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.javalang.Reflections;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Preconditions;
-
-/**
- * Miscellaneous tasks which are useful in effectors.
- * @since 0.6.0
- */
-@Beta
-public class EffectorTasks {
-
-    @SuppressWarnings("unused")
-    private static final Logger log = LoggerFactory.getLogger(EffectorTasks.class);
-    
-    public interface EffectorTaskFactory<T> {
-        public abstract TaskAdaptable<T> newTask(Entity entity, Effector<T> effector, ConfigBag parameters);
-    }
-    
-    /** wrapper for {@link EffectorBody} which simply runs that body on each invocation;
-     * the body must be thread safe and ideally stateless */
-    public static class EffectorBodyTaskFactory<T> implements EffectorTaskFactory<T> {
-        private final EffectorBody<T> effectorBody;
-        public EffectorBodyTaskFactory(EffectorBody<T> effectorBody) {
-            this.effectorBody = effectorBody;
-        }
-        
-        @Override
-        public Task<T> newTask(final Entity entity, final org.apache.brooklyn.api.effector.Effector<T> effector, final ConfigBag parameters) {
-            final AtomicReference<DynamicSequentialTask<T>> dst = new AtomicReference<DynamicSequentialTask<T>>();
-
-            dst.set(new DynamicSequentialTask<T>(
-                    getFlagsForTaskInvocationAt(entity, effector, parameters), 
-                    new Callable<T>() {
-                        @Override
-                        public T call() throws Exception {
-                            try {
-                                DynamicTasks.setTaskQueueingContext(dst.get());
-                                return effectorBody.call(parameters);
-                            } finally {
-                                DynamicTasks.removeTaskQueueingContext();
-                            }
-                        }
-                    }) {
-                        @Override
-                        public void handleException(Throwable throwable) throws Exception {
-                            EffectorUtils.handleEffectorException(entity, effector, throwable);
-                        }
-                    });
-            return dst.get();
-        };
-
-        /** @deprecated since 0.7.0 use {@link #getFlagsForTaskInvocationAt(Entity, Effector, ConfigBag)} */ @Deprecated
-        protected final Map<Object,Object> getFlagsForTaskInvocationAt(Entity entity, Effector<?> effector) {
-            return getFlagsForTaskInvocationAt(entity, effector, null);
-        }
-        /** subclasses may override to add additional flags, but they should include the flags returned here 
-         * unless there is very good reason not to; default impl returns a MutableMap */
-        protected Map<Object,Object> getFlagsForTaskInvocationAt(Entity entity, Effector<?> effector, ConfigBag parameters) {
-            return EffectorUtils.getTaskFlagsForEffectorInvocation(entity, effector, parameters);
-        }
-    }
-    
-    /** wrapper for {@link EffectorTaskFactory} which ensures effector task tags are applied to it if needed
-     * (wrapping in a task if needed); without this, {@link EffectorBody}-based effectors get it by
-     * virtue of the call to {@link #getFlagsForTaskInvocationAt(Entity,Effector,ConfigBag)} therein
-     * but {@link EffectorTaskFactory}-based effectors generate a task without the right tags
-     * to be able to tell using {@link BrooklynTaskTags} the effector-context of the task 
-     * <p>
-     * this gets applied automatically so marked as package-private */
-    static class EffectorMarkingTaskFactory<T> implements EffectorTaskFactory<T> {
-        private final EffectorTaskFactory<T> effectorTaskFactory;
-        public EffectorMarkingTaskFactory(EffectorTaskFactory<T> effectorTaskFactory) {
-            this.effectorTaskFactory = effectorTaskFactory;
-        }
-        
-        @Override
-        public Task<T> newTask(final Entity entity, final org.apache.brooklyn.api.effector.Effector<T> effector, final ConfigBag parameters) {
-            if (effectorTaskFactory instanceof EffectorBodyTaskFactory)
-                return effectorTaskFactory.newTask(entity, effector, parameters).asTask();
-            // if we're in an effector context for this effector already, then also pass through
-            if (BrooklynTaskTags.isInEffectorTask(Tasks.current(), entity, effector, false))
-                return effectorTaskFactory.newTask(entity, effector, parameters).asTask();
-            // otherwise, create the task inside an appropriate effector body so tags, name, etc are set correctly
-            return new EffectorBodyTaskFactory<T>(new EffectorBody<T>() {
-                @Override
-                public T call(ConfigBag parameters) {
-                    TaskAdaptable<T> t = DynamicTasks.queue(effectorTaskFactory.newTask(entity, effector, parameters));
-                    return t.asTask().getUnchecked();
-                }
-            }).newTask(entity, effector, parameters);
-        }
-    }
-    
-    public static <T> ConfigKey<T> asConfigKey(ParameterType<T> t) {
-        return ConfigKeys.newConfigKey(t.getParameterClass(), t.getName());
-    }
-    
-    public static <T> ParameterTask<T> parameter(ParameterType<T> t) {
-        return new ParameterTask<T>(asConfigKey(t)).
-                name("parameter "+t);
-    }
-    public static <T> ParameterTask<T> parameter(Class<T> type, String name) {
-        return new ParameterTask<T>(ConfigKeys.newConfigKey(type, name)).
-                name("parameter "+name+" ("+type+")");
-    }
-    public static <T> ParameterTask<T> parameter(final ConfigKey<T> p) {
-        return new ParameterTask<T>(p);
-    }
-    public static class ParameterTask<T> implements EffectorTaskFactory<T> {
-        final ConfigKey<T> p;
-        private TaskBuilder<T> builder;
-        public ParameterTask(ConfigKey<T> p) {
-            this.p = p;
-            this.builder = Tasks.<T>builder().name("parameter "+p);
-        }
-        public ParameterTask<T> name(String taskName) {
-            builder.name(taskName);
-            return this;
-        }
-        @Override
-        public Task<T> newTask(Entity entity, Effector<T> effector, final ConfigBag parameters) {
-            return builder.body(new Callable<T>() {
-                @Override
-                public T call() throws Exception {
-                    return parameters.get(p);
-                }
-                
-            }).build();
-        }
-        
-    }
-
-    public static <T> EffectorTaskFactory<T> of(final Task<T> task) {
-        return new EffectorTaskFactory<T>() {
-            @Override
-            public Task<T> newTask(Entity entity, Effector<T> effector, ConfigBag parameters) {
-                return task;
-            }
-        };
-    }
-
-    /** Finds the entity where this task is running
-     * @throws NullPointerException if there is none (no task, or no context entity for that task) */
-    public static Entity findEntity() {
-        return Preconditions.checkNotNull(BrooklynTaskTags.getTargetOrContextEntity(Tasks.current()),
-                "This must be executed in a task whose execution context has a target or context entity " +
-                "(i.e. it must be run from within an effector)");
-    }
-
-    /** Finds the entity where this task is running, casted to the given Entity subtype
-     * @throws NullPointerException if there is none
-     * @throws IllegalArgumentException if it is not of the indicated type */
-    public static <T extends Entity> T findEntity(Class<T> type) {
-        Entity t = findEntity();
-        return Reflections.cast(t, type);
-    }
-
-    /** Finds a unique {@link SshMachineLocation} attached to the entity 
-     * where this task is running
-     * @throws NullPointerException if {@link #findEntity()} fails
-     * @throws IllegalStateException if call to {@link #getSshMachine(Entity)} fails */
-    public static SshMachineLocation findSshMachine() {
-        return getSshMachine(findEntity());
-    }
-
-    /** Finds a unique {@link SshMachineLocation} attached to the supplied entity 
-     * @throws IllegalStateException if there is not a unique such {@link SshMachineLocation} */
-    public static SshMachineLocation getSshMachine(Entity entity) {
-        try {
-            return Machines.findUniqueSshMachineLocation(entity.getLocations()).get();
-        } catch (Exception e) {
-            throw new IllegalStateException("Entity "+entity+" (in "+Tasks.current()+") requires a single SshMachineLocation, but has "+entity.getLocations(), e);
-        }
-    }
-
-    /** Finds a unique {@link WinRmMachineLocation} attached to the supplied entity
-     * @throws IllegalStateException if there is not a unique such {@link WinRmMachineLocation} */
-    public static WinRmMachineLocation getWinRmMachine(Entity entity) {
-        try {
-            return Machines.findUniqueWinRmMachineLocation(entity.getLocations()).get();
-        } catch (Exception e) {
-            throw new IllegalStateException("Entity "+entity+" (in "+Tasks.current()+") requires a single WinRmMachineLocation, but has "+entity.getLocations(), e);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/effector/core/EffectorWithBody.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/effector/core/EffectorWithBody.java b/core/src/main/java/org/apache/brooklyn/effector/core/EffectorWithBody.java
deleted file mode 100644
index 6ba2d30..0000000
--- a/core/src/main/java/org/apache/brooklyn/effector/core/EffectorWithBody.java
+++ /dev/null
@@ -1,32 +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.effector.core;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.effector.core.EffectorTasks.EffectorTaskFactory;
-
-import com.google.common.annotations.Beta;
-
-@Beta // added in 0.6.0
-public interface EffectorWithBody<T> extends Effector<T> {
-
-    /** returns the body of the effector, i.e. a factory which can generate tasks which can run */
-    public EffectorTaskFactory<T> getBody();
-    
-}


[29/36] incubator-brooklyn git commit: Rename o.a.b.sensor.enricher to o.a.b.core.enricher

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricherDeprecatedTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricherDeprecatedTest.groovy b/core/src/test/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricherDeprecatedTest.groovy
deleted file mode 100644
index b35c329..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricherDeprecatedTest.groovy
+++ /dev/null
@@ -1,367 +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 org.testng.Assert.assertEquals
-
-import org.apache.brooklyn.api.entity.EntitySpec
-import org.apache.brooklyn.api.sensor.AttributeSensor
-import org.apache.brooklyn.core.test.entity.TestApplication
-import org.apache.brooklyn.core.test.entity.TestEntity
-import org.apache.brooklyn.core.entity.Entities
-import org.apache.brooklyn.entity.group.BasicGroup
-import org.apache.brooklyn.core.location.SimulatedLocation
-import org.apache.brooklyn.core.sensor.BasicAttributeSensor
-import org.apache.brooklyn.test.TestUtils
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import org.testng.annotations.AfterMethod
-import org.testng.annotations.BeforeMethod
-import org.testng.annotations.Test
-
-import com.google.common.base.Function
-
-class CustomAggregatingEnricherDeprecatedTest {
-
-    public static final Logger log = LoggerFactory.getLogger(CustomAggregatingEnricherDeprecatedTest.class);
-            
-    private static final long TIMEOUT_MS = 10*1000
-    private static final long SHORT_WAIT_MS = 250
-    
-    TestApplication app
-    TestEntity producer
-    
-    AttributeSensor<Integer> intSensor
-    AttributeSensor<Integer> target
-
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() {
-        app = TestApplication.Factory.newManagedInstanceForTests();
-        producer = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        intSensor = new BasicAttributeSensor<Integer>(Integer.class, "int sensor")
-        target = new BasicAttributeSensor<Integer>(Long.class, "target sensor")
-        
-        app.start([new SimulatedLocation()])
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() {
-        if (app!=null) Entities.destroyAll(app.getManagementContext());
-    }
-    
-    @Test
-    public void testEnrichersWithNoProducers() {
-        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher([:], intSensor, target, 11, 40)
-        producer.addEnricher(cae)
-        assertEquals cae.getAggregate(), 40
-    }
-
-    @Test
-    public void testSummingEnricherWhenNoSensorValuesYet() {
-        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(
-                intSensor, target, producers:[producer], 11, 40)
-        producer.addEnricher(cae)
-        assertEquals cae.getAggregate(), 11
-    }
-
-    @Test
-    public void testSingleProducerSum() {
-        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(
-                intSensor, target, null, null, producers:[producer])
-        producer.addEnricher(cae)
-        assertEquals cae.getAggregate(), null
-        cae.onEvent(intSensor.newEvent(producer, 1))
-        assertEquals cae.getAggregate(), 1
-    }
-    
-    @Test
-    public void testSummingEnricherWhenNoAndNullSensorValue() {
-        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(
-                intSensor, target, null, null, producers:[producer])
-        producer.addEnricher(cae)
-        assertEquals cae.getAggregate(), null
-        cae.onEvent(intSensor.newEvent(producer, null))
-        assertEquals cae.getAggregate(), null
-    }
-    
-    @Test
-    public void testSummingEnricherWhenNoAndNullSensorValueExplicitValue() {
-        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(
-                intSensor, target, 3 /** if null */, 5 /** if none */, producers:[producer])
-        producer.addEnricher(cae)
-        assertEquals cae.getAggregate(), 3
-        cae.onEvent(intSensor.newEvent(producer, null))
-        assertEquals cae.getAggregate(), 3
-        cae.onEvent(intSensor.newEvent(producer, 1))
-        assertEquals cae.getAggregate(), 1
-        cae.onEvent(intSensor.newEvent(producer, 7))
-        assertEquals cae.getAggregate(), 7
-    }
-    
-    @Test
-    public void testMultipleProducersSum() {
-        List<TestEntity> producers = [
-                app.createAndManageChild(EntitySpec.create(TestEntity.class)), 
-                app.createAndManageChild(EntitySpec.create(TestEntity.class)),
-                app.createAndManageChild(EntitySpec.create(TestEntity.class))
-                ]
-        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(
-            intSensor, target, null, null, producers:producers)
-        
-        producer.addEnricher(cae)
-        assertEquals cae.getAggregate(), null
-        cae.onEvent(intSensor.newEvent(producers[2], 1))
-        assertEquals cae.getAggregate(), 1
-        cae.onEvent(intSensor.newEvent(producers[0], 3))
-        assertEquals cae.getAggregate(), 4
-        cae.onEvent(intSensor.newEvent(producers[1], 3))
-        assertEquals cae.getAggregate(), 7
-
-    }
-    
-    @Test
-    public void testAveragingEnricherWhenNoAndNullSensorValues() {
-        List<TestEntity> producers = [ 
-                app.createAndManageChild(EntitySpec.create(TestEntity.class))
-                ]
-        CustomAggregatingEnricher<Double> cae = CustomAggregatingEnricher.<Double>newAveragingEnricher(
-                intSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), null, null, producers:producers)
-        producer.addEnricher(cae)
-        assertEquals cae.getAggregate(), null
-        cae.onEvent(intSensor.newEvent(producers[0], null))
-        assertEquals cae.getAggregate(), null
-    }
-
-    @Test
-    public void testAveragingEnricherWhenNoAndNullSensorValuesExplicit() {
-        List<TestEntity> producers = [
-                app.createAndManageChild(EntitySpec.create(TestEntity.class))
-                ]
-        CustomAggregatingEnricher<Double> cae = CustomAggregatingEnricher.<Double>newAveragingEnricher(
-                intSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), 3 /** if null */, 5 /** if none */,
-                producers:producers)
-        producer.addEnricher(cae)
-        
-        assertEquals cae.getAggregate(), 3d
-        cae.onEvent(intSensor.newEvent(producers[0], null))
-        assertEquals cae.getAggregate(), 3d
-        cae.onEvent(intSensor.newEvent(producers[0], 4))
-        assertEquals cae.getAggregate(), 4d
-    }
-
-    @Test
-    public void testAveragingEnricherWhenNoSensors() {
-        List<TestEntity> producers = [
-                ]
-        CustomAggregatingEnricher<Double> cae = CustomAggregatingEnricher.<Double>newAveragingEnricher(
-                intSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), 3 /** if null */, 5 /** if none */,
-                producers:producers)
-        producer.addEnricher(cae)
-        
-        assertEquals cae.getAggregate(), 5d
-    }
-
-    @Test
-    public void testMultipleProducersAverage() {
-        List<TestEntity> producers = [
-                app.createAndManageChild(EntitySpec.create(TestEntity.class)), 
-                app.createAndManageChild(EntitySpec.create(TestEntity.class)),
-                app.createAndManageChild(EntitySpec.create(TestEntity.class))
-                ]
-        CustomAggregatingEnricher<Double> cae = CustomAggregatingEnricher.<Double>newAveragingEnricher(
-                intSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), null, null, producers:producers)
-        
-        producer.addEnricher(cae)
-        
-        assertEquals cae.getAggregate(), null
-        cae.onEvent(intSensor.newEvent(producers[0], 3))
-        assertEquals cae.getAggregate(), 3d
-        
-        cae.onEvent(intSensor.newEvent(producers[1], 3))
-        assertEquals cae.getAggregate(), 3d
-        
-        cae.onEvent(intSensor.newEvent(producers[2], 6))
-        assertEquals cae.getAggregate(), 4d
-
-        // change p2's value to 7.5, average increase of 0.5.
-        cae.onEvent(intSensor.newEvent(producers[2], 7.5))
-        assertEquals cae.getAggregate(), 4.5d
-    }
-    
-    @Test
-    public void testMultipleProducersAverageDefaultingZero() {
-        List<TestEntity> producers = [
-                app.createAndManageChild(EntitySpec.create(TestEntity.class)), 
-                app.createAndManageChild(EntitySpec.create(TestEntity.class)),
-                app.createAndManageChild(EntitySpec.create(TestEntity.class))
-                ]
-        CustomAggregatingEnricher<Double> cae = CustomAggregatingEnricher.<Double>newAveragingEnricher(
-                intSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), 0, 0, producers:producers)
-        
-        producer.addEnricher(cae)
-        
-        assertEquals cae.getAggregate(), 0d
-        cae.onEvent(intSensor.newEvent(producers[0], 3))
-        assertEquals cae.getAggregate(), 1d
-        
-        cae.onEvent(intSensor.newEvent(producers[1], 3))
-        assertEquals cae.getAggregate(), 2d
-        
-        cae.onEvent(intSensor.newEvent(producers[2], 6))
-        assertEquals cae.getAggregate(), 4d
-
-        // change p2's value to 7.5, average increase of 0.5.
-        cae.onEvent(intSensor.newEvent(producers[2], 7.5))
-        assertEquals cae.getAggregate(), 4.5d
-    }
-    
-    @Test
-    public void testAddingAndRemovingProducers() {
-        TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class)); 
-        TestEntity p2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        
-        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(
-                intSensor, target, null, null, producers:[p1])
-
-        producer.addEnricher(cae)
-        assertEquals cae.getAggregate(), null
-        
-        // Event by initial producer
-        cae.onEvent(intSensor.newEvent(p1, 1))
-        assertEquals cae.getAggregate(), 1
-        
-        // Add producer and fire event
-        cae.addProducer(p2)
-        cae.onEvent(intSensor.newEvent(p2, 4))
-        assertEquals cae.getAggregate(), 5
-        
-        cae.removeProducer(p2)
-        assertEquals cae.getAggregate(), 1
-    }
-    
-    @Test
-    public void testAggregatesNewMembersOfGroup() {
-        try {
-            BasicGroup group = app.createAndManageChild(EntitySpec.create(BasicGroup.class));
-            TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class))
-            TestEntity p2 = app.createAndManageChild(EntitySpec.create(TestEntity.class))
-            log.debug("created $group and the entities it will contain $p1 $p2")
-
-            CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(intSensor, target, 0, 0, allMembers:true)
-            group.addEnricher(cae)
-
-            assertEquals cae.getAggregate(), 0
-
-            group.addMember(p1)
-            p1.setAttribute(intSensor, 1)
-            TestUtils.executeUntilSucceeds(timeout:TIMEOUT_MS) {
-                assertEquals cae.getAggregate(), 1
-            }
-
-            group.addMember(p2)
-            p2.setAttribute(intSensor, 2)
-            TestUtils.executeUntilSucceeds(timeout:TIMEOUT_MS) {
-                assertEquals cae.getAggregate(), 3
-            }
-
-            group.removeMember(p2)
-            TestUtils.executeUntilSucceeds(timeout:TIMEOUT_MS) {
-                assertEquals cae.getAggregate(), 1
-            }
-        } catch (Exception e) {
-            log.error("testAggregatesNewMembersOfGroup failed (now cleaning up): "+e)
-            throw e;
-        }
-    }
-    
-    @Test(groups = "Integration")
-    public void testAggregatesGroupMembersFiftyTimes() {
-        for (int i=0; i<50; i++) {
-            log.debug "testAggregatesNewMembersOfGroup $i"
-            testAggregatesNewMembersOfGroup();
-        }
-    }
-    
-    @Test
-    public void testAggregatesExistingMembersOfGroup() {
-        BasicGroup group = app.addChild(EntitySpec.create(BasicGroup.class));
-        TestEntity p1 = app.getManagementContext().getEntityManager().createEntity(EntitySpec.create(TestEntity.class).parent(group)); 
-        TestEntity p2 = app.getManagementContext().getEntityManager().createEntity(EntitySpec.create(TestEntity.class).parent(group)); 
-        group.addMember(p1)
-        group.addMember(p2)
-        p1.setAttribute(intSensor, 1)
-        Entities.manage(group);
-        
-        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(intSensor, target, null, null, allMembers:true)
-        group.addEnricher(cae)
-        
-        assertEquals cae.getAggregate(), 1
-
-        p2.setAttribute(intSensor, 2)
-        TestUtils.executeUntilSucceeds(timeout:TIMEOUT_MS) {
-            assertEquals cae.getAggregate(), 3
-        }
-        
-        group.removeMember(p2)
-        TestUtils.executeUntilSucceeds(timeout:TIMEOUT_MS) {
-            assertEquals cae.getAggregate(), 1
-        }
-    }
-    
-    @Test
-    public void testAppliesFilterWhenAggregatingMembersOfGroup() {
-        BasicGroup group = app.createAndManageChild(EntitySpec.create(BasicGroup.class));
-        TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        TestEntity p2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        TestEntity p3 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        group.addMember(p1)
-        group.addMember(p2)
-        p1.setAttribute(intSensor, 1)
-        p2.setAttribute(intSensor, 2)
-        p3.setAttribute(intSensor, 4)
-        
-        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(intSensor, target, null, null, allMembers:true, filter:{it == p1})
-        group.addEnricher(cae)
-        
-        assertEquals cae.getAggregate(), 1
-        
-        group.addMember(p3)
-        TestUtils.assertSucceedsContinually(timeout:SHORT_WAIT_MS) {
-            assertEquals cae.getAggregate(), 1
-        }
-    }
-    
-    @Test
-    public void testCustomAggregatingFunction() {
-        TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class)); 
-        Function<Collection<Integer>,Integer> aggregator = { Collection c -> 
-            int result = 0; c.each { result += it*it }; return result;
-        } as Function
-         
-        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newEnricher(
-                intSensor, target, aggregator, 0, producers:[p1])
-
-        producer.addEnricher(cae)
-        assertEquals cae.getAggregate(), 0
-        
-        // Event by producer
-        cae.onEvent(intSensor.newEvent(p1, 2))
-        assertEquals cae.getAggregate(), 4
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricherTest.java b/core/src/test/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricherTest.java
deleted file mode 100644
index 30737b7..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricherTest.java
+++ /dev/null
@@ -1,556 +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 org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.location.LocationSpec;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.location.SimulatedLocation;
-import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
-import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.entity.group.BasicGroup;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Function;
-import com.google.common.base.Predicates;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-public class CustomAggregatingEnricherTest extends BrooklynAppUnitTestSupport {
-
-    public static final Logger log = LoggerFactory.getLogger(CustomAggregatingEnricherTest.class);
-            
-    private static final long TIMEOUT_MS = 10*1000;
-    private static final long SHORT_WAIT_MS = 50;
-    
-    TestEntity entity;
-    SimulatedLocation loc;
-    
-    AttributeSensor<Integer> intSensor;
-    AttributeSensor<Double> doubleSensor;
-    AttributeSensor<Integer> target;
-
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        intSensor = new BasicAttributeSensor<Integer>(Integer.class, "int sensor");
-        doubleSensor = new BasicAttributeSensor<Double>(Double.class, "double sensor");
-        target = new BasicAttributeSensor<Integer>(Integer.class, "target sensor");
-        loc = mgmt.getLocationManager().createLocation(LocationSpec.create(SimulatedLocation.class));
-        app.start(ImmutableList.of(loc));
-    }
-    
-    @Test
-    public void testSummingEnricherWithNoProducersDefaultsToNull() {
-        entity.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(target)
-                .computingSum()
-                .fromChildren()
-                .build());
-        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 50), entity, target, null);
-    }
-
-    @Test
-    public void testSummingEnricherWithNoProducers() {
-        entity.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(target)
-                .computingSum()
-                .fromChildren()
-                .defaultValueForUnreportedSensors(11)
-                .valueToReportIfNoSensors(40)
-                .build());
-        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 40);
-    }
-
-    @Test
-    public void testSummingEnricherWhenNoSensorValuesYet() {
-        entity.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(target)
-                .computingSum()
-                .fromHardcodedProducers(ImmutableList.of(entity))
-                .defaultValueForUnreportedSensors(11)
-                .valueToReportIfNoSensors(40)
-                .build());
-        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 11);
-    }
-
-    @Test
-    public void testSummingEnricherWhenNoSensorValuesYetDefaultsToNull() {
-        entity.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(target)
-                .computingSum()
-                .fromHardcodedProducers(ImmutableList.of(entity))
-                .build());
-        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 50), entity, target, null);
-    }
-
-    @Test
-    public void testSummingEnricherWithNoValues() {
-        entity.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(target)
-                .computingSum()
-                .fromHardcodedProducers(ImmutableList.of(entity))
-                .build());
-        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 50), entity, target, null);
-    }
-    
-    @Test
-    public void testSummingEnricherWithOneValue() {
-        entity.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(target)
-                .computingSum()
-                .fromHardcodedProducers(ImmutableList.of(entity))
-                .build());
-
-        entity.setAttribute(intSensor, 1);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 1);
-    }
-    
-    @Test
-    public void testSummingEnricherWhenNullSensorValue() {
-        entity.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(target)
-                .computingSum()
-                .fromHardcodedProducers(ImmutableList.of(entity))
-                .build());
-
-        entity.setAttribute(intSensor, null);
-        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 50), entity, target, null);
-    }
-    
-    @Test
-    public void testSummingEnricherWhenDefaultValueForUnreportedSensors() {
-        entity.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(target)
-                .computingSum()
-                .fromHardcodedProducers(ImmutableList.of(entity))
-                .defaultValueForUnreportedSensors(3)
-                .valueToReportIfNoSensors(5)
-                .build());
-
-        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 3);
-        
-        entity.setAttribute(intSensor, null);
-        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 50), entity, target, 3);
-        
-        entity.setAttribute(intSensor, 1);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 1);
-        
-        entity.setAttribute(intSensor, 7);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 7);
-    }
-    
-    @Test
-    public void testMultipleProducersSum() {
-        TestEntity producer1 = app.createAndManageChild(EntitySpec.create(TestEntity.class)); 
-        TestEntity producer2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        TestEntity producer3 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-
-        entity.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(target)
-                .computingSum()
-                .fromHardcodedProducers(ImmutableList.of(producer1, producer2, producer3))
-                .build());
-
-        producer3.setAttribute(intSensor, 1);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 1);
-
-        producer1.setAttribute(intSensor, 2);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 3);
-
-        producer2.setAttribute(intSensor, 4);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 7);
-    }
-    
-    @Test
-    public void testAveragingEnricherWhenNoAndNullSensorValues() {
-        TestEntity producer1 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        
-        entity.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(doubleSensor)
-                .computingAverage()
-                .fromHardcodedProducers(ImmutableList.of(producer1))
-                .build());
-
-        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 50), entity, doubleSensor, null);
-        
-        producer1.setAttribute(intSensor, null);
-        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 50), entity, doubleSensor, null);
-    }
-
-    @Test
-    public void testAveragingEnricherWhenDefaultValueForUnreportedSensors() {
-        TestEntity producer1 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        
-        entity.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(doubleSensor)
-                .computingAverage()
-                .fromHardcodedProducers(ImmutableList.of(producer1))
-                .defaultValueForUnreportedSensors(3)
-                .valueToReportIfNoSensors(5)
-                .build());
-
-        EntityTestUtils.assertAttributeEqualsEventually(entity, doubleSensor, 3d);
-        
-        producer1.setAttribute(intSensor, null);
-        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 50), entity, doubleSensor, 3d);
-        
-        producer1.setAttribute(intSensor, 4);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, doubleSensor, 4d);
-    }
-
-    @Test
-    public void testAveragingEnricherWhenNoSensors() {
-        entity.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(doubleSensor)
-                .computingAverage()
-                .fromChildren()
-                .defaultValueForUnreportedSensors(3)
-                .valueToReportIfNoSensors(5)
-                .build());
-
-        EntityTestUtils.assertAttributeEqualsEventually(entity, doubleSensor, 5d);
-    }
-
-    @Test
-    public void testAveragingEnricherWhenNoProducersDefaultsToNull() {
-        entity.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(doubleSensor)
-                .computingAverage()
-                .fromChildren()
-                .build());
-
-        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 50), entity, doubleSensor, null);
-    }
-
-    @Test
-    public void testMultipleProducersAverage() {
-        TestEntity producer1 = app.createAndManageChild(EntitySpec.create(TestEntity.class)); 
-        TestEntity producer2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        TestEntity producer3 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        
-        entity.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(doubleSensor)
-                .computingAverage()
-                .fromHardcodedProducers(ImmutableList.of(producer1, producer2, producer3))
-                .build());
-
-        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 50), entity, doubleSensor, null);
-
-        producer1.setAttribute(intSensor, 3);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, doubleSensor, 3d);
-        
-        producer2.setAttribute(intSensor, 1);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, doubleSensor, 2d);
-
-        producer3.setAttribute(intSensor, 5);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, doubleSensor, 3d);
-
-        producer2.setAttribute(intSensor, 4);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, doubleSensor, 4d);
-    }
-    
-    @Test
-    public void testMultipleProducersAverageDefaultingZero() {
-        TestEntity producer1 = app.createAndManageChild(EntitySpec.create(TestEntity.class)); 
-        TestEntity producer2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        TestEntity producer3 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        
-        entity.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(doubleSensor)
-                .computingAverage()
-                .fromHardcodedProducers(ImmutableList.of(producer1, producer2, producer3))
-                .defaultValueForUnreportedSensors(0)
-                .valueToReportIfNoSensors(0)
-                .build());
-
-        EntityTestUtils.assertAttributeEqualsEventually(entity, doubleSensor, 0d);
-
-        producer1.setAttribute(intSensor, 3);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, doubleSensor, 1d);
-
-        producer2.setAttribute(intSensor, 3);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, doubleSensor, 2d);
-
-        producer3.setAttribute(intSensor, 3);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, doubleSensor, 3d);
-    }
-    
-    @Test
-    public void testAggregatesNewMembersOfGroup() {
-        BasicGroup group = app.createAndManageChild(EntitySpec.create(BasicGroup.class));
-        TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        TestEntity p2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        log.debug("created {} and the entities it will contain {} {}", new Object[] {group, p1, p2});
-
-        group.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(target)
-                .computingSum()
-                .fromMembers()
-                .defaultValueForUnreportedSensors(0)
-                .valueToReportIfNoSensors(0)
-                .build());
-
-        EntityTestUtils.assertAttributeEqualsEventually(group, target, 0);
-
-        group.addMember(p1);
-        p1.setAttribute(intSensor, 1);
-        EntityTestUtils.assertAttributeEqualsEventually(group, target, 1);
-
-        group.addMember(p2);
-        p2.setAttribute(intSensor, 2);
-        EntityTestUtils.assertAttributeEqualsEventually(group, target, 3);
-
-        group.removeMember(p2);
-        EntityTestUtils.assertAttributeEqualsEventually(group, target, 1);
-    }
-    
-    @Test(groups = "Integration", invocationCount=50)
-    public void testAggregatesGroupMembersFiftyTimes() {
-        testAggregatesNewMembersOfGroup();
-    }
-    
-    @Test
-    public void testAggregatesExistingMembersOfGroup() {
-        BasicGroup group = app.addChild(EntitySpec.create(BasicGroup.class));
-        TestEntity p1 = app.getManagementContext().getEntityManager().createEntity(EntitySpec.create(TestEntity.class).parent(group)); 
-        TestEntity p2 = app.getManagementContext().getEntityManager().createEntity(EntitySpec.create(TestEntity.class).parent(group)); 
-        group.addMember(p1);
-        group.addMember(p2);
-        p1.setAttribute(intSensor, 1);
-        Entities.manage(group);
-        
-        group.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(target)
-                .computingSum()
-                .fromMembers()
-                .build());
-
-
-        EntityTestUtils.assertAttributeEqualsEventually(group, target, 1);
-
-        p2.setAttribute(intSensor, 2);
-        EntityTestUtils.assertAttributeEqualsEventually(group, target, 3);
-        
-        group.removeMember(p2);
-        EntityTestUtils.assertAttributeEqualsEventually(group, target, 1);
-    }
-    
-    @Test
-    public void testAggregatesMembersOfProducer() {
-        BasicGroup group = app.addChild(EntitySpec.create(BasicGroup.class));
-        TestEntity p1 = app.getManagementContext().getEntityManager().createEntity(EntitySpec.create(TestEntity.class).parent(group)); 
-        TestEntity p2 = app.getManagementContext().getEntityManager().createEntity(EntitySpec.create(TestEntity.class).parent(group)); 
-        group.addMember(p1);
-        group.addMember(p2);
-        p1.setAttribute(intSensor, 1);
-        Entities.manage(group);
-        
-        app.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(target)
-                .computingSum()
-                .from(group)
-                .fromMembers()
-                .build());
-
-
-        EntityTestUtils.assertAttributeEqualsEventually(app, target, 1);
-
-        p2.setAttribute(intSensor, 2);
-        EntityTestUtils.assertAttributeEqualsEventually(app, target, 3);
-        
-        group.removeMember(p2);
-        EntityTestUtils.assertAttributeEqualsEventually(app, target, 1);
-    }
-    
-    @Test
-    public void testAppliesFilterWhenAggregatingMembersOfGroup() {
-        BasicGroup group = app.createAndManageChild(EntitySpec.create(BasicGroup.class));
-        TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        TestEntity p2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        TestEntity p3 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        group.addMember(p1);
-        group.addMember(p2);
-        p1.setAttribute(intSensor, 1);
-        p2.setAttribute(intSensor, 2);
-        p3.setAttribute(intSensor, 4);
-        
-        group.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(target)
-                .computingSum()
-                .fromMembers()
-                .entityFilter(Predicates.equalTo((Entity)p1))
-                .build());
-
-        EntityTestUtils.assertAttributeEqualsEventually(group, target, 1);
-        
-        group.addMember(p3);
-        EntityTestUtils.assertAttributeEqualsContinually(ImmutableMap.of("timeout", SHORT_WAIT_MS), group, target, 1);
-    }
-    
-    @Test
-    public void testAggregatesNewChidren() {
-        entity.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(target)
-                .computingSum()
-                .fromChildren()
-                .defaultValueForUnreportedSensors(0)
-                .valueToReportIfNoSensors(0)
-                .build());
-
-        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 0);
-
-        TestEntity p1 = entity.createAndManageChild(EntitySpec.create(TestEntity.class));
-        p1.setAttribute(intSensor, 1);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 1);
-
-        TestEntity p2 = entity.createAndManageChild(EntitySpec.create(TestEntity.class));
-        p2.setAttribute(intSensor, 2);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 3);
-
-        Entities.unmanage(p2);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 1);
-    }
-    
-    @Test
-    public void testAggregatesExistingChildren() {
-        TestEntity p1 = entity.createAndManageChild(EntitySpec.create(TestEntity.class));
-        TestEntity p2 = entity.createAndManageChild(EntitySpec.create(TestEntity.class));
-        p1.setAttribute(intSensor, 1);
-        
-        entity.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(target)
-                .computingSum()
-                .fromChildren()
-                .build());
-
-
-        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 1);
-
-        p2.setAttribute(intSensor, 2);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 3);
-        
-        Entities.unmanage(p2);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 1);
-    }
-    
-    @Test
-    public void testAggregatesChildrenOfProducer() {
-        TestEntity p1 = entity.createAndManageChild(EntitySpec.create(TestEntity.class));
-        TestEntity p2 = entity.createAndManageChild(EntitySpec.create(TestEntity.class));
-        p1.setAttribute(intSensor, 1);
-        
-        app.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(target)
-                .computingSum()
-                .from(entity)
-                .fromChildren()
-                .build());
-
-
-        EntityTestUtils.assertAttributeEqualsEventually(app, target, 1);
-
-        p2.setAttribute(intSensor, 2);
-        EntityTestUtils.assertAttributeEqualsEventually(app, target, 3);
-        
-        Entities.unmanage(p2);
-        EntityTestUtils.assertAttributeEqualsEventually(app, target, 1);
-    }
-    
-    @Test
-    public void testAppliesFilterWhenAggregatingChildrenOfGroup() {
-        TestEntity p1 = entity.createAndManageChild(EntitySpec.create(TestEntity.class));
-        p1.setAttribute(intSensor, 1);
-        
-        entity.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(target)
-                .computingSum()
-                .fromChildren()
-                .entityFilter(Predicates.equalTo((Entity)p1))
-                .build());
-
-        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 1);
-        
-        TestEntity p2 = entity.createAndManageChild(EntitySpec.create(TestEntity.class));
-        p2.setAttribute(intSensor, 2);
-        EntityTestUtils.assertAttributeEqualsContinually(ImmutableMap.of("timeout", SHORT_WAIT_MS), entity, target, 1);
-    }
-    
-    @Test
-    public void testCustomAggregatingFunction() {
-        TestEntity producer1 = app.createAndManageChild(EntitySpec.create(TestEntity.class)); 
-        Function<Collection<Integer>,Integer> aggregator = new Function<Collection<Integer>, Integer>() {
-            public Integer apply(Collection<Integer> input) { 
-                int result = 1;
-                for (Integer in : input) result += in*in;
-                return result;
-            }
-        };
-        
-        entity.addEnricher(Enrichers.builder()
-                .aggregating(intSensor)
-                .publishing(target)
-                .computing(aggregator)
-                .fromHardcodedProducers(ImmutableList.of(producer1))
-                .defaultValueForUnreportedSensors(0)
-                .build());
-
-        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 1);
-        
-        // Event by producer
-        producer1.setAttribute(intSensor, 2);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, target, 5);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/sensor/enricher/EnricherConfigTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/enricher/EnricherConfigTest.java b/core/src/test/java/org/apache/brooklyn/sensor/enricher/EnricherConfigTest.java
deleted file mode 100644
index 9015d19..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/enricher/EnricherConfigTest.java
+++ /dev/null
@@ -1,147 +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 org.testng.Assert.assertEquals;
-import static org.testng.Assert.fail;
-
-import org.apache.brooklyn.core.config.BasicConfigKey;
-import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.sensor.enricher.BasicEnricherTest.MyEnricher;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.testng.annotations.Test;
-
-/**
- * Test that configuration properties are usable and inherited correctly.
- */
-public class EnricherConfigTest extends BrooklynAppUnitTestSupport {
-    
-    // TODO These tests are a copy of PolicyConfigTest, which is a code smell.
-    // However, the src/main/java code does not contain as much duplication.
-    
-    private BasicConfigKey<String> differentKey = new BasicConfigKey<String>(String.class, "differentkey", "diffval");
-
-    @Test
-    public void testConfigFlagsPassedInAtConstructionIsAvailable() throws Exception {
-        MyEnricher enricher = new MyEnricher(MutableMap.builder()
-                .put("strKey", "aval")
-                .put("intKey", 2)
-                .build());
-        app.addEnricher(enricher);
-        
-        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval");
-        assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2);
-        // this is set, because key name matches annotation on STR_KEY
-        assertEquals(enricher.getConfig(MyEnricher.STR_KEY_WITH_DEFAULT), "aval");
-    }
-    
-    @Test
-    public void testUnknownConfigPassedInAtConstructionIsWarnedAndIgnored() throws Exception {
-        // TODO Also assert it's warned
-        MyEnricher enricher = new MyEnricher(MutableMap.builder()
-                .put(differentKey, "aval")
-                .build());
-        app.addEnricher(enricher);
-        
-        assertEquals(enricher.getConfig(differentKey), null);
-        assertEquals(enricher.getEnricherType().getConfigKey(differentKey.getName()), null);
-    }
-    
-    @Test
-    public void testConfigPassedInAtConstructionIsAvailable() throws Exception {
-        MyEnricher enricher = new MyEnricher(MutableMap.builder()
-                .put(MyEnricher.STR_KEY, "aval")
-                .put(MyEnricher.INT_KEY, 2)
-                .build());
-        app.addEnricher(enricher);
-        
-        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval");
-        assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2);
-        // this is not set (contrast with above)
-        assertEquals(enricher.getConfig(MyEnricher.STR_KEY_WITH_DEFAULT), MyEnricher.STR_KEY_WITH_DEFAULT.getDefaultValue());
-    }
-    
-    @Test
-    public void testConfigSetToGroovyTruthFalseIsAvailable() throws Exception {
-        MyEnricher enricher = new MyEnricher(MutableMap.builder()
-                .put(MyEnricher.INT_KEY_WITH_DEFAULT, 0)
-                .build());
-        app.addEnricher(enricher);
-        
-        assertEquals(enricher.getConfig(MyEnricher.INT_KEY_WITH_DEFAULT), (Integer)0);
-    }
-    
-    @Test
-    public void testConfigSetToNullIsAvailable() throws Exception {
-        MyEnricher enricher = new MyEnricher(MutableMap.builder()
-                .put(MyEnricher.STR_KEY_WITH_DEFAULT, null)
-                .build());
-        app.addEnricher(enricher);
-        
-        assertEquals(enricher.getConfig(MyEnricher.STR_KEY_WITH_DEFAULT), null);
-    }
-    
-    @Test
-    public void testConfigCanBeSetOnEnricher() throws Exception {
-        MyEnricher enricher = new MyEnricher();
-        enricher.config().set(MyEnricher.STR_KEY, "aval");
-        enricher.config().set(MyEnricher.INT_KEY, 2);
-        app.addEnricher(enricher);
-        
-        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval");
-        assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2);
-    }
-    
-    @Test
-    public void testConfigSetterOverridesConstructorValue() throws Exception {
-        MyEnricher enricher = new MyEnricher(MutableMap.builder()
-                .put(MyEnricher.STR_KEY, "aval")
-                .build());
-        enricher.config().set(MyEnricher.STR_KEY, "diffval");
-        app.addEnricher(enricher);
-        
-        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "diffval");
-    }
-
-    @Test
-    public void testConfigCannotBeSetAfterApplicationIsStarted() throws Exception {
-        MyEnricher enricher = new MyEnricher(MutableMap.builder()
-                .put(MyEnricher.STR_KEY, "origval")
-                .build());
-        app.addEnricher(enricher);
-        
-        try {
-            enricher.config().set(MyEnricher.STR_KEY,"newval");
-            fail();
-        } catch (UnsupportedOperationException e) {
-            // success
-        }
-        
-        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "origval");
-    }
-    
-    @Test
-    public void testConfigReturnsDefaultValueIfNotSet() throws Exception {
-        MyEnricher enricher = new MyEnricher();
-        app.addEnricher(enricher);
-        
-        assertEquals(enricher.getConfig(MyEnricher.STR_KEY_WITH_DEFAULT), "str key default");
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/sensor/enricher/EnrichersTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/enricher/EnrichersTest.java b/core/src/test/java/org/apache/brooklyn/sensor/enricher/EnrichersTest.java
deleted file mode 100644
index ff76342..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/enricher/EnrichersTest.java
+++ /dev/null
@@ -1,501 +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.EntitySpec;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.api.sensor.Enricher;
-import org.apache.brooklyn.api.sensor.SensorEvent;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.EntityAdjuncts;
-import org.apache.brooklyn.core.entity.RecordingSensorEventListener;
-import org.apache.brooklyn.core.sensor.Sensors;
-import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.entity.group.BasicGroup;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
-import org.apache.brooklyn.test.Asserts;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.apache.brooklyn.util.collections.CollectionFunctionals;
-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.guava.Functionals;
-import org.apache.brooklyn.util.text.StringFunctions;
-import org.testng.Assert;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-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;
-import com.google.common.collect.Iterables;
-import com.google.common.reflect.TypeToken;
-
-@SuppressWarnings("serial")
-public class EnrichersTest extends BrooklynAppUnitTestSupport {
-
-    public static final AttributeSensor<Integer> NUM1 = Sensors.newIntegerSensor("test.num1");
-    public static final AttributeSensor<Integer> NUM2 = Sensors.newIntegerSensor("test.num2");
-    public static final AttributeSensor<Integer> NUM3 = Sensors.newIntegerSensor("test.num3");
-    public static final AttributeSensor<String> STR1 = Sensors.newStringSensor("test.str1");
-    public static final AttributeSensor<String> STR2 = Sensors.newStringSensor("test.str2");
-    public static final AttributeSensor<Set<Object>> SET1 = Sensors.newSensor(new TypeToken<Set<Object>>() {}, "test.set1", "set1 descr");
-    public static final AttributeSensor<Long> LONG1 = Sensors.newLongSensor("test.long1");
-    public static final AttributeSensor<Map<String,String>> MAP1 = Sensors.newSensor(new TypeToken<Map<String,String>>() {}, "test.map1", "map1 descr");
-    @SuppressWarnings("rawtypes")
-    public static final AttributeSensor<Map> MAP2 = Sensors.newSensor(Map.class, "test.map2");
-    
-    private TestEntity entity;
-    private TestEntity entity2;
-    private BasicGroup group;
-    
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        entity2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        group = app.createAndManageChild(EntitySpec.create(BasicGroup.class));
-    }
-    
-    @SuppressWarnings("unchecked")
-    @Test
-    public void testAdding() {
-        Enricher enr = entity.addEnricher(Enrichers.builder()
-                .combining(NUM1, NUM2)
-                .publishing(NUM3)
-                .computingSum()
-                .build());
-        
-        Assert.assertEquals(EntityAdjuncts.getNonSystemEnrichers(entity), ImmutableList.of(enr));
-        
-        entity.setAttribute(NUM1, 2);
-        entity.setAttribute(NUM2, 3);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, NUM3, 5);
-    }
-    
-    @SuppressWarnings("unchecked")
-    @Test
-    public void testCombiningWithCustomFunction() {
-        entity.addEnricher(Enrichers.builder()
-                .combining(NUM1, NUM2)
-                .publishing(NUM3)
-                .computing(Functions.constant(1))
-                .build());
-        
-        entity.setAttribute(NUM1, 2);
-        entity.setAttribute(NUM2, 3);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, NUM3, 1);
-    }
-    
-    @SuppressWarnings("unchecked")
-    @Test(groups="Integration") // because takes a second
-    public void testCombiningRespectsUnchanged() {
-        entity.addEnricher(Enrichers.builder()
-                .combining(NUM1, NUM2)
-                .<Object>publishing(NUM3)
-                .computing(new Function<Iterable<Integer>, Object>() {
-                        @Override public Object apply(Iterable<Integer> input) {
-                            if (input != null && Iterables.contains(input, 123)) {
-                                return Enrichers.sum(input, 0, 0, new TypeToken<Integer>(){});
-                            } else {
-                                return Entities.UNCHANGED;
-                            }
-                        }})
-                .build());
-        
-        entity.setAttribute(NUM1, 123);
-        entity.setAttribute(NUM2, 3);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, NUM3, 126);
-        
-        entity.setAttribute(NUM1, 2);
-        EntityTestUtils.assertAttributeEqualsContinually(entity, NUM3, 126);
-    }
-    
-    @Test
-    public void testFromEntity() {
-        entity.addEnricher(Enrichers.builder()
-                .transforming(NUM1)
-                .publishing(NUM1)
-                .computing(Functions.<Integer>identity())
-                .from(entity2)
-                .build());
-        
-        entity2.setAttribute(NUM1, 2);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, NUM1, 2);
-    }
-    
-    @Test
-    public void testTransforming() {
-        entity.addEnricher(Enrichers.builder()
-                .transforming(STR1)
-                .publishing(STR2)
-                .computing(StringFunctions.append("mysuffix"))
-                .build());
-        
-        entity.setAttribute(STR1, "myval");
-        EntityTestUtils.assertAttributeEqualsEventually(entity, STR2, "myvalmysuffix");
-    }
-
-    @Test
-    public void testTransformingCastsResult() {
-        entity.addEnricher(Enrichers.builder()
-                .transforming(NUM1)
-                .publishing(LONG1)
-                .computing(Functions.constant(Long.valueOf(1)))
-                .build());
-        
-        entity.setAttribute(NUM1, 123);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, LONG1, Long.valueOf(1));
-    }
-
-    @Test
-    public void testTransformingFromEvent() {
-        entity.addEnricher(Enrichers.builder()
-                .transforming(STR1)
-                .publishing(STR2)
-                .computingFromEvent(new Function<SensorEvent<String>, String>() {
-                    @Override public String apply(SensorEvent<String> input) {
-                        return input.getValue() + "mysuffix";
-                    }})
-                .build());
-        
-        entity.setAttribute(STR1, "myval");
-        EntityTestUtils.assertAttributeEqualsEventually(entity, STR2, "myvalmysuffix");
-    }
-
-    @Test(groups="Integration") // because takes a second
-    public void testTransformingRespectsUnchangedButWillRepublish() {
-        RecordingSensorEventListener<String> record = new RecordingSensorEventListener<>();
-        app.getManagementContext().getSubscriptionManager().subscribe(entity, STR2, record);
-        
-        entity.addEnricher(Enrichers.builder()
-                .transforming(STR1)
-                .<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.getEvents(), CollectionFunctionals.sizeEquals(0));
-
-        entity.setAttribute(STR1, "myval");
-        Asserts.eventually(Suppliers.ofInstance(record), 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), 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), CollectionFunctionals.sizeEquals(5));
-    }
-
-    public void testTransformingSuppressDuplicates() {
-        RecordingSensorEventListener<String> 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), 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.getEvents(), CollectionFunctionals.sizeEquals(3));
-    }
-
-    @Test
-    public void testPropagating() {
-        entity.addEnricher(Enrichers.builder()
-                .propagating(ImmutableList.of(STR1))
-                .from(entity2)
-                .build());
-        
-        entity2.setAttribute(STR1, "myval");
-        EntityTestUtils.assertAttributeEqualsEventually(entity, STR1, "myval");
-        
-        entity2.setAttribute(STR1, null);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, STR1, null);
-    }
-    
-    @Test
-    public void testPropagatingAndRenaming() {
-        entity.addEnricher(Enrichers.builder()
-                .propagating(ImmutableMap.of(STR1, STR2))
-                .from(entity2)
-                .build());
-        
-        entity2.setAttribute(STR1, "myval");
-        EntityTestUtils.assertAttributeEqualsEventually(entity, STR2, "myval");
-    }
-    
-    // FIXME What is default? members? children? fail?
-    @Test
-    public void testAggregatingGroupSum() {
-        TestEntity child1 = group.addChild(EntitySpec.create(TestEntity.class));
-        Entities.manage(child1);
-        group.addMember(entity);
-        group.addMember(entity2);
-        group.addEnricher(Enrichers.builder()
-                .aggregating(NUM1)
-                .publishing(NUM2)
-                .fromMembers()
-                .computingSum()
-                .build());
-        
-        child1.setAttribute(NUM1, 1);
-        entity.setAttribute(NUM1, 2);
-        entity2.setAttribute(NUM1, 3);
-        EntityTestUtils.assertAttributeEqualsEventually(group, NUM2, 5);
-    }
-    
-    @Test
-    public void testAggregatingChildrenSum() {
-        group.addMember(entity);
-        TestEntity child1 = group.addChild(EntitySpec.create(TestEntity.class));
-        Entities.manage(child1);
-        TestEntity child2 = group.addChild(EntitySpec.create(TestEntity.class));
-        Entities.manage(child2);
-        group.addEnricher(Enrichers.builder()
-                .aggregating(NUM1)
-                .publishing(NUM2)
-                .fromChildren()
-                .computingSum()
-                .build());
-        
-        entity.setAttribute(NUM1, 1);
-        child1.setAttribute(NUM1, 2);
-        child2.setAttribute(NUM1, 3);
-        EntityTestUtils.assertAttributeEqualsEventually(group, NUM2, 5);
-    }
-
-    @Test
-    public void testAggregatingExcludingBlankString() {
-        group.addMember(entity);
-        group.addMember(entity2);
-        group.addEnricher(Enrichers.builder()
-                .aggregating(STR1)
-                .publishing(SET1)
-                .fromMembers()
-                .excludingBlank()
-                .computing(new Function<Collection<?>, Set<Object>>() {
-                    @Override public Set<Object> apply(Collection<?> input) {
-                        // accept null values, so don't use ImmutableSet
-                        return (input == null) ? ImmutableSet.<Object>of() : MutableSet.<Object>copyOf(input);
-                    }})
-                .build());
-        
-        entity.setAttribute(STR1, "1");
-        entity2.setAttribute(STR1, "2");
-        EntityTestUtils.assertAttributeEqualsEventually(group, SET1, ImmutableSet.<Object>of("1", "2"));
-        
-        entity.setAttribute(STR1, "3");
-        entity2.setAttribute(STR1, null);
-        EntityTestUtils.assertAttributeEqualsEventually(group, SET1, ImmutableSet.<Object>of("3"));
-        
-        entity.setAttribute(STR1, "");
-        entity2.setAttribute(STR1, "4");
-        EntityTestUtils.assertAttributeEqualsEventually(group, SET1, ImmutableSet.<Object>of("4"));
-    }
-
-    @Test
-    public void testAggregatingExcludingNull() {
-        group.addMember(entity);
-        group.addEnricher(Enrichers.builder()
-                .aggregating(NUM1)
-                .publishing(SET1)
-                .fromMembers()
-                .excludingBlank()
-                .computing(new Function<Collection<?>, Set<Object>>() {
-                    @Override public Set<Object> apply(Collection<?> input) {
-                        // accept null values, so don't use ImmutableSet
-                        return (input == null) ? ImmutableSet.<Object>of() : MutableSet.<Object>copyOf(input);
-                    }})
-                .build());
-
-        EntityTestUtils.assertAttributeEqualsEventually(group, SET1, ImmutableSet.<Object>of());
-
-        entity.setAttribute(NUM1, 1);
-        EntityTestUtils.assertAttributeEqualsEventually(group, SET1, ImmutableSet.<Object>of(1));
-        
-        entity.setAttribute(NUM1, null);
-        EntityTestUtils.assertAttributeEqualsEventually(group, SET1, ImmutableSet.<Object>of());
-        
-        entity.setAttribute(NUM1, 2);
-        EntityTestUtils.assertAttributeEqualsEventually(group, SET1, ImmutableSet.<Object>of(2));
-    }
-
-    @Test
-    public void testAggregatingCastsResult() {
-        group.addMember(entity);
-        group.addEnricher(Enrichers.builder()
-                .aggregating(NUM1)
-                .publishing(LONG1)
-                .fromMembers()
-                .computing(Functions.constant(Long.valueOf(1)))
-                .build());
-        
-        entity.setAttribute(NUM1, 123);
-        EntityTestUtils.assertAttributeEqualsEventually(group, LONG1, Long.valueOf(1));
-    }
-    
-    @Test(groups="Integration") // because takes a second
-    public void testAggregatingRespectsUnchanged() {
-        group.addMember(entity);
-        group.addEnricher(Enrichers.builder()
-                .aggregating(NUM1)
-                .<Object>publishing(LONG1)
-                .fromMembers()
-                .computing(new Function<Iterable<Integer>, Object>() {
-                        @Override public Object apply(Iterable<Integer> input) {
-                            if (input != null && Iterables.contains(input, 123)) {
-                                return Enrichers.sum(input, 0, 0, new TypeToken<Integer>(){});
-                            } else {
-                                return Entities.UNCHANGED;
-                            }
-                        }})
-                .build());
-        
-        entity.setAttribute(NUM1, 123);
-        EntityTestUtils.assertAttributeEqualsEventually(group, LONG1, Long.valueOf(123));
-        
-        entity.setAttribute(NUM1, 987654);
-        EntityTestUtils.assertAttributeEqualsContinually(group, LONG1, Long.valueOf(123));
-    }
-    @Test
-    public void testUpdatingMap1() {
-        entity.addEnricher(Enrichers.builder()
-                .updatingMap(MAP1)
-                .from(LONG1)
-                .computing(Functionals.ifEquals(-1L).value("-1 is not allowed"))
-                .build());
-        
-        doUpdatingMapChecks(MAP1);
-    }
-    
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Test
-    public void testUpdatingMap2() {
-        entity.addEnricher(Enrichers.builder()
-                .updatingMap((AttributeSensor)MAP2)
-                .from(LONG1)
-                .computing(Functionals.ifEquals(-1L).value("-1 is not allowed"))
-                .build());
-        
-        doUpdatingMapChecks(MAP2);
-    }
-    
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    protected void doUpdatingMapChecks(AttributeSensor mapSensor) {
-        EntityTestUtils.assertAttributeEqualsEventually(entity, mapSensor, MutableMap.<String,String>of());
-        
-        entity.setAttribute(LONG1, -1L);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, mapSensor, MutableMap.<String,String>of(
-            LONG1.getName(), "-1 is not allowed"));
-        
-        entity.setAttribute(LONG1, 1L);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, mapSensor, MutableMap.<String,String>of());
-    }
-
-    private static AttributeSensor<Object> LIST_SENSOR = Sensors.newSensor(Object.class, "sensor.list");
-    
-    @Test
-    public void testJoinerDefault() {
-        entity.addEnricher(Enrichers.builder()
-                .joining(LIST_SENSOR)
-                .publishing(TestEntity.NAME)
-                .build());
-        // null values ignored, and it quotes
-        entity.setAttribute(LIST_SENSOR, MutableList.<String>of("a", "\"b").append(null));
-        EntityTestUtils.assertAttributeEqualsEventually(entity, TestEntity.NAME, "\"a\",\"\\\"b\"");
-        
-        // empty list causes ""
-        entity.setAttribute(LIST_SENSOR, MutableList.<String>of().append(null));
-        EntityTestUtils.assertAttributeEqualsEventually(entity, TestEntity.NAME, "");
-        
-        // null causes null
-        entity.setAttribute(LIST_SENSOR, null);
-        EntityTestUtils.assertAttributeEqualsEventually(entity, TestEntity.NAME, null);
-    }
-
-    @Test
-    public void testJoinerUnquoted() {
-        entity.setAttribute(LIST_SENSOR, MutableList.<String>of("a", "\"b", "ccc").append(null));
-        entity.addEnricher(Enrichers.builder()
-            .joining(LIST_SENSOR)
-            .publishing(TestEntity.NAME)
-            .minimum(1)
-            .maximum(2)
-            .separator(":")
-            .quote(false)
-            .build());
-        // in this case, it should be immediately available upon adding the enricher
-        EntityTestUtils.assertAttributeEquals(entity, TestEntity.NAME, "a:\"b");
-        
-        // empty list causes null here, because below the minimum
-        entity.setAttribute(LIST_SENSOR, MutableList.<String>of().append(null));
-        EntityTestUtils.assertAttributeEqualsEventually(entity, TestEntity.NAME, null);
-    }
-
-    @Test
-    public void testJoinerMinMax() {
-        entity.addEnricher(Enrichers.builder()
-                .joining(LIST_SENSOR)
-                .publishing(TestEntity.NAME)
-                .minimum(2)
-                .maximum(4)
-                .quote(false)
-                .build());
-        // null values ignored, and it quotes
-        entity.setAttribute(LIST_SENSOR, MutableList.<String>of("a", "b"));
-        EntityTestUtils.assertAttributeEqualsEventually(entity, TestEntity.NAME, "a,b");
-        
-        // empty list causes ""
-        entity.setAttribute(LIST_SENSOR, MutableList.<String>of("x"));
-        EntityTestUtils.assertAttributeEqualsEventually(entity, TestEntity.NAME, null);
-        
-        // null causes null
-        entity.setAttribute(LIST_SENSOR, MutableList.<String>of("a", "b", "c", "d", "e"));
-        EntityTestUtils.assertAttributeEqualsEventually(entity, TestEntity.NAME, "a,b,c,d");
-    }
-
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricherDeprecatedTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricherDeprecatedTest.java b/core/src/test/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricherDeprecatedTest.java
deleted file mode 100644
index 9b55006..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricherDeprecatedTest.java
+++ /dev/null
@@ -1,108 +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.concurrent.atomic.AtomicReference;
-
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.api.sensor.SensorEvent;
-import org.apache.brooklyn.api.sensor.SensorEventListener;
-import org.apache.brooklyn.core.sensor.Sensors;
-import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.enricher.SensorPropagatingEnricher;
-import org.apache.brooklyn.test.Asserts;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.javalang.AtomicReferences;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Predicates;
-import com.google.common.collect.ImmutableMap;
-
-public class SensorPropagatingEnricherDeprecatedTest extends BrooklynAppUnitTestSupport {
-
-    private TestEntity entity;
-
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-    }
-    
-    @Test
-    public void testPropagatesSpecificSensor() {
-        app.addEnricher(SensorPropagatingEnricher.newInstanceListeningTo(entity, TestEntity.NAME));
-
-        // name propagated
-        entity.setAttribute(TestEntity.NAME, "foo");
-        EntityTestUtils.assertAttributeEqualsEventually(app, TestEntity.NAME, "foo");
-        
-        // sequence not propagated
-        entity.setAttribute(TestEntity.SEQUENCE, 2);
-        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 100), app, TestEntity.SEQUENCE, null);
-    }
-    
-    @Test
-    public void testPropagatesAllSensors() {
-        app.addEnricher(SensorPropagatingEnricher.newInstanceListeningToAllSensors(entity));
-
-        // all attributes propagated
-        entity.setAttribute(TestEntity.NAME, "foo");
-        entity.setAttribute(TestEntity.SEQUENCE, 2);
-        
-        EntityTestUtils.assertAttributeEqualsEventually(app, TestEntity.NAME, "foo");
-        EntityTestUtils.assertAttributeEqualsEventually(app, TestEntity.SEQUENCE, 2);
-        
-        // notification-sensor propagated
-        final AtomicReference<Integer> notif = new AtomicReference<Integer>();
-        app.subscribe(app, TestEntity.MY_NOTIF, new SensorEventListener<Integer>() {
-                @Override public void onEvent(SensorEvent<Integer> event) {
-                    notif.set(event.getValue());
-                }});
-        entity.emit(TestEntity.MY_NOTIF, 7);
-        Asserts.eventually(AtomicReferences.supplier(notif), Predicates.equalTo(7));
-    }
-    
-    @Test
-    public void testPropagatesAllBut() {
-        app.addEnricher(SensorPropagatingEnricher.newInstanceListeningToAllSensorsBut(entity, TestEntity.SEQUENCE)) ;
-
-        // name propagated
-        entity.setAttribute(TestEntity.NAME, "foo");
-        EntityTestUtils.assertAttributeEqualsEventually(app, TestEntity.NAME, "foo");
-        
-        // sequence not propagated
-        entity.setAttribute(TestEntity.SEQUENCE, 2);
-        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 100), app, TestEntity.SEQUENCE, null);
-    }
-    
-    @Test
-    public void testPropagatingAsDifferentSensor() {
-        final AttributeSensor<String> ANOTHER_ATTRIBUTE = Sensors.newStringSensor("another.attribute", "");
-        app.addEnricher(SensorPropagatingEnricher.newInstanceRenaming(entity, ImmutableMap.of(TestEntity.NAME, ANOTHER_ATTRIBUTE)));
-
-        // name propagated as different attribute
-        entity.setAttribute(TestEntity.NAME, "foo");
-        EntityTestUtils.assertAttributeEqualsEventually(app, ANOTHER_ATTRIBUTE, "foo");
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricherTest.java b/core/src/test/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricherTest.java
deleted file mode 100644
index 82067c4..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricherTest.java
+++ /dev/null
@@ -1,218 +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.concurrent.atomic.AtomicReference;
-
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.api.sensor.EnricherSpec;
-import org.apache.brooklyn.api.sensor.SensorEvent;
-import org.apache.brooklyn.api.sensor.SensorEventListener;
-import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
-import org.apache.brooklyn.core.sensor.Sensors;
-import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
-import org.apache.brooklyn.sensor.enricher.Propagator;
-import org.apache.brooklyn.test.Asserts;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.javalang.AtomicReferences;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Predicates;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-public class SensorPropagatingEnricherTest extends BrooklynAppUnitTestSupport {
-
-    private TestEntity entity;
-
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-    }
-    
-    @Test
-    public void testPropagatesSpecificSensor() {
-        app.addEnricher(Enrichers.builder()
-                .propagating(TestEntity.NAME)
-                .from(entity)
-                .build());
-
-        // name propagated
-        entity.setAttribute(TestEntity.NAME, "foo");
-        EntityTestUtils.assertAttributeEqualsEventually(app, TestEntity.NAME, "foo");
-        
-        // sequence not propagated
-        entity.setAttribute(TestEntity.SEQUENCE, 2);
-        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 100), app, TestEntity.SEQUENCE, null);
-    }
-    
-    @Test
-    public void testPropagatesCurrentValue() {
-        entity.setAttribute(TestEntity.NAME, "foo");
-        
-        app.addEnricher(Enrichers.builder()
-                .propagating(TestEntity.NAME)
-                .from(entity)
-                .build());
-
-        // name propagated
-        EntityTestUtils.assertAttributeEqualsEventually(app, TestEntity.NAME, "foo");
-    }
-    
-    @Test
-    public void testPropagatesAllStaticSensors() {
-        app.addEnricher(Enrichers.builder()
-                .propagatingAll()
-                .from(entity)
-                .build());
-
-        // all attributes propagated
-        entity.setAttribute(TestEntity.NAME, "foo");
-        entity.setAttribute(TestEntity.SEQUENCE, 2);
-        
-        EntityTestUtils.assertAttributeEqualsEventually(app, TestEntity.NAME, "foo");
-        EntityTestUtils.assertAttributeEqualsEventually(app, TestEntity.SEQUENCE, 2);
-        
-        // notification-sensor propagated
-        final AtomicReference<Integer> notif = new AtomicReference<Integer>();
-        app.subscribe(app, TestEntity.MY_NOTIF, new SensorEventListener<Integer>() {
-                @Override public void onEvent(SensorEvent<Integer> event) {
-                    notif.set(event.getValue());
-                }});
-        entity.emit(TestEntity.MY_NOTIF, 7);
-        Asserts.eventually(AtomicReferences.supplier(notif), Predicates.equalTo(7));
-    }
-    
-    @Test
-    public void testPropagatesAllSensorsIncludesDynamicallyAdded() {
-        AttributeSensor<String> dynamicAttribute = Sensors.newStringSensor("test.dynamicsensor.strattrib");
-        BasicNotificationSensor<String> dynamicNotificationSensor = new BasicNotificationSensor(String.class, "test.dynamicsensor.strnotif");
-        
-        app.addEnricher(Enrichers.builder()
-                .propagatingAll()
-                .from(entity)
-                .build());
-
-        entity.setAttribute(dynamicAttribute, "foo");
-        
-        EntityTestUtils.assertAttributeEqualsEventually(app, dynamicAttribute, "foo");
-        
-        // notification-sensor propagated
-        final AtomicReference<String> notif = new AtomicReference<String>();
-        app.subscribe(app, dynamicNotificationSensor, new SensorEventListener<String>() {
-                @Override public void onEvent(SensorEvent<String> event) {
-                    notif.set(event.getValue());
-                }});
-        entity.emit(dynamicNotificationSensor, "mynotifval");
-        Asserts.eventually(AtomicReferences.supplier(notif), Predicates.equalTo("mynotifval"));
-    }
-    
-    @Test
-    public void testPropagatesAllBut() {
-        app.addEnricher(Enrichers.builder()
-                .propagatingAllBut(TestEntity.SEQUENCE)
-                .from(entity)
-                .build());
-
-        // name propagated
-        entity.setAttribute(TestEntity.NAME, "foo");
-        EntityTestUtils.assertAttributeEqualsEventually(app, TestEntity.NAME, "foo");
-        
-        // sequence not propagated
-        entity.setAttribute(TestEntity.SEQUENCE, 2);
-        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 100), app, TestEntity.SEQUENCE, null);
-    }
-    
-    @Test
-    public void testPropagatingAsDifferentSensor() {
-        final AttributeSensor<String> ANOTHER_ATTRIBUTE = Sensors.newStringSensor("another.attribute", "");
-        
-        app.addEnricher(Enrichers.builder()
-                .propagating(ImmutableMap.of(TestEntity.NAME, ANOTHER_ATTRIBUTE))
-                .from(entity)
-                .build());
-
-        // name propagated as different attribute
-        entity.setAttribute(TestEntity.NAME, "foo");
-        EntityTestUtils.assertAttributeEqualsEventually(app, ANOTHER_ATTRIBUTE, "foo");
-    }
-    
-    @Test
-    public void testEnricherSpecPropagatesSpecificSensor() throws Exception {
-        app.addEnricher(EnricherSpec.create(Propagator.class)
-                .configure(MutableMap.builder()
-                        .putIfNotNull(Propagator.PRODUCER, entity)
-                        .putIfNotNull(Propagator.PROPAGATING, ImmutableList.of(TestEntity.NAME))
-                        .build()));
-
-        // name propagated
-        entity.setAttribute(TestEntity.NAME, "foo");
-        EntityTestUtils.assertAttributeEqualsEventually(app, TestEntity.NAME, "foo");
-        
-        // sequence not propagated
-        entity.setAttribute(TestEntity.SEQUENCE, 2);
-        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 100), app, TestEntity.SEQUENCE, null);
-    }
-    
-    @Test
-    public void testEnricherSpecPropagatesSpecificSensorAndMapsOthers() throws Exception {
-        final AttributeSensor<String> ANOTHER_ATTRIBUTE = Sensors.newStringSensor("another.attribute", "");
-        
-        app.addEnricher(EnricherSpec.create(Propagator.class)
-                .configure(MutableMap.builder()
-                        .putIfNotNull(Propagator.PRODUCER, entity)
-                        .putIfNotNull(Propagator.SENSOR_MAPPING, ImmutableMap.of(TestEntity.NAME, ANOTHER_ATTRIBUTE))
-                        .putIfNotNull(Propagator.PROPAGATING, ImmutableList.of(TestEntity.SEQUENCE))
-                        .build()));
-
-        // name propagated as alternative sensor
-        entity.setAttribute(TestEntity.NAME, "foo");
-        EntityTestUtils.assertAttributeEqualsEventually(app, ANOTHER_ATTRIBUTE, "foo");
-        
-        // sequence also propagated
-        entity.setAttribute(TestEntity.SEQUENCE, 2);
-        EntityTestUtils.assertAttributeEqualsEventually(app, TestEntity.SEQUENCE, 2);
-
-        // name not propagated as original sensor
-        EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", 100), app, TestEntity.NAME, null);
-    }
-    
-    @Test
-    public void testEnricherSpecThrowsOnPropagatesAndPropagatesAllSet() throws Exception {
-        try {
-            app.addEnricher(EnricherSpec.create(Propagator.class)
-                    .configure(MutableMap.builder()
-                            .put(Propagator.PRODUCER, entity)
-                            .put(Propagator.PROPAGATING, ImmutableList.of(TestEntity.NAME))
-                            .put(Propagator.PROPAGATING_ALL, true)
-                            .build()));
-        } catch (Exception e) {
-            IllegalStateException ise = Exceptions.getFirstThrowableOfType(e, IllegalStateException.class);
-            if (ise == null) throw e;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/sensor/enricher/TransformingEnricherDeprecatedTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/enricher/TransformingEnricherDeprecatedTest.groovy b/core/src/test/java/org/apache/brooklyn/sensor/enricher/TransformingEnricherDeprecatedTest.groovy
deleted file mode 100644
index 9db0d37..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/enricher/TransformingEnricherDeprecatedTest.groovy
+++ /dev/null
@@ -1,82 +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.concurrent.Callable
-
-import org.apache.brooklyn.api.entity.EntitySpec
-import org.apache.brooklyn.api.sensor.AttributeSensor
-import org.apache.brooklyn.core.test.entity.TestApplication
-import org.apache.brooklyn.core.test.entity.TestEntity
-import org.apache.brooklyn.core.entity.Entities
-import org.apache.brooklyn.core.location.SimulatedLocation
-import org.apache.brooklyn.core.sensor.BasicAttributeSensor
-import org.apache.brooklyn.test.TestUtils
-import org.apache.brooklyn.util.collections.MutableMap
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import org.testng.Assert
-import org.testng.annotations.AfterMethod
-import org.testng.annotations.BeforeMethod
-import org.testng.annotations.Test
-
-public class TransformingEnricherDeprecatedTest {
-
-    public static final Logger log = LoggerFactory.getLogger(TransformingEnricherDeprecatedTest.class);
-            
-    private static final long TIMEOUT_MS = 10*1000;
-//    private static final long SHORT_WAIT_MS = 250;
-    
-    TestApplication app;
-    TestEntity producer;
-    AttributeSensor<Integer> intSensorA;
-    AttributeSensor<Long> target;
-
-    @BeforeMethod()
-    public void before() {
-        app = TestApplication.Factory.newManagedInstanceForTests();
-        producer = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        intSensorA = new BasicAttributeSensor<Integer>(Integer.class, "int.sensor.a");
-        target = new BasicAttributeSensor<Long>(Long.class, "long.sensor.target");
-        
-        app.start(Arrays.asList(new SimulatedLocation()));
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    public void after() {
-        if (app!=null) Entities.destroyAll(app.getManagementContext());
-    }
-    
-    @Test
-    public void testTransformingEnricher() throws InterruptedException {
-        final SensorTransformingEnricher e1 = new SensorTransformingEnricher<Integer,Long>(intSensorA, target, 
-            { 2*it });
-        
-        producer.setAttribute(intSensorA, 3);
-        //ensure previous values get picked up
-        producer.addEnricher(e1);
-
-        TestUtils.assertEventually(MutableMap.of("timeout", TIMEOUT_MS), 
-                new Callable<Object>() { public Object call() {
-                    Assert.assertEquals(producer.getAttribute(target), (Long)((long)6));
-                    return null;
-                }});
-
-    }
-}


[27/36] incubator-brooklyn git commit: Rename o.a.b.sensor.feed to o.a.b.feed and o.a.b.core.feed

Posted by he...@apache.org.
Rename o.a.b.sensor.feed to o.a.b.feed and o.a.b.core.feed

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

Branch: refs/heads/master
Commit: daf40919b6fa20f16b6cd7d9eb1ad9f79baaa8f4
Parents: 2a78e27
Author: Aled Sage <al...@gmail.com>
Authored: Wed Aug 19 22:56:13 2015 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Wed Aug 19 22:56:13 2015 +0100

----------------------------------------------------------------------
 .../brooklyn/core/entity/AbstractEntity.java    |   4 +-
 .../apache/brooklyn/core/feed/AbstractFeed.java | 240 ++++++
 .../core/feed/AttributePollHandler.java         | 248 +++++++
 .../brooklyn/core/feed/ConfigToAttributes.java  |  59 ++
 .../core/feed/DelegatingPollHandler.java        |  96 +++
 .../apache/brooklyn/core/feed/FeedConfig.java   | 297 ++++++++
 .../apache/brooklyn/core/feed/PollConfig.java   |  85 +++
 .../apache/brooklyn/core/feed/PollHandler.java  |  38 +
 .../org/apache/brooklyn/core/feed/Poller.java   | 205 ++++++
 .../mgmt/rebind/BasicEntityRebindSupport.java   |   2 +-
 .../mgmt/rebind/BasicFeedRebindSupport.java     |   2 +-
 .../core/mgmt/rebind/RebindIteration.java       |   2 +-
 .../mgmt/rebind/dto/MementosGenerators.java     |   2 +-
 .../sensor/AttributeSensorAndConfigKey.java     |   2 +-
 .../brooklyn/core/sensor/HttpRequestSensor.java |   6 +-
 .../entity/group/DynamicMultiGroupImpl.java     |   4 +-
 .../brooklyn/entity/stock/DataEntityImpl.java   |   4 +-
 .../brooklyn/feed/function/FunctionFeed.java    | 208 ++++++
 .../feed/function/FunctionPollConfig.java       | 111 +++
 .../org/apache/brooklyn/feed/http/HttpFeed.java | 382 ++++++++++
 .../brooklyn/feed/http/HttpPollConfig.java      | 160 ++++
 .../brooklyn/feed/http/HttpPollValue.java       |  40 +
 .../apache/brooklyn/feed/http/HttpPolls.java    |  39 +
 .../brooklyn/feed/http/HttpValueFunctions.java  | 154 ++++
 .../brooklyn/feed/http/JsonFunctions.java       | 235 ++++++
 .../apache/brooklyn/feed/shell/ShellFeed.java   | 273 +++++++
 .../brooklyn/feed/shell/ShellPollConfig.java    | 125 ++++
 .../org/apache/brooklyn/feed/ssh/SshFeed.java   | 290 ++++++++
 .../apache/brooklyn/feed/ssh/SshPollConfig.java | 142 ++++
 .../apache/brooklyn/feed/ssh/SshPollValue.java  |  60 ++
 .../brooklyn/feed/ssh/SshValueFunctions.java    |  73 ++
 .../windows/WindowsPerformanceCounterFeed.java  | 412 +++++++++++
 .../WindowsPerformanceCounterPollConfig.java    |  53 ++
 .../brooklyn/sensor/feed/AbstractFeed.java      | 240 ------
 .../sensor/feed/AttributePollHandler.java       | 248 -------
 .../sensor/feed/ConfigToAttributes.java         |  59 --
 .../sensor/feed/DelegatingPollHandler.java      |  96 ---
 .../apache/brooklyn/sensor/feed/FeedConfig.java | 297 --------
 .../apache/brooklyn/sensor/feed/PollConfig.java |  85 ---
 .../brooklyn/sensor/feed/PollHandler.java       |  38 -
 .../org/apache/brooklyn/sensor/feed/Poller.java | 205 ------
 .../sensor/feed/function/FunctionFeed.java      | 208 ------
 .../feed/function/FunctionPollConfig.java       | 111 ---
 .../brooklyn/sensor/feed/http/HttpFeed.java     | 382 ----------
 .../sensor/feed/http/HttpPollConfig.java        | 160 ----
 .../sensor/feed/http/HttpPollValue.java         |  40 -
 .../brooklyn/sensor/feed/http/HttpPolls.java    |  39 -
 .../sensor/feed/http/HttpValueFunctions.java    | 154 ----
 .../sensor/feed/http/JsonFunctions.java         | 235 ------
 .../brooklyn/sensor/feed/shell/ShellFeed.java   | 273 -------
 .../sensor/feed/shell/ShellPollConfig.java      | 125 ----
 .../brooklyn/sensor/feed/ssh/SshFeed.java       | 290 --------
 .../brooklyn/sensor/feed/ssh/SshPollConfig.java | 142 ----
 .../brooklyn/sensor/feed/ssh/SshPollValue.java  |  60 --
 .../sensor/feed/ssh/SshValueFunctions.java      |  73 --
 .../windows/WindowsPerformanceCounterFeed.java  | 412 -----------
 .../WindowsPerformanceCounterPollConfig.java    |  53 --
 .../util/core/http/HttpToolResponse.java        |   2 +-
 .../core/feed/ConfigToAttributesTest.java       |  70 ++
 .../apache/brooklyn/core/feed/PollerTest.java   | 108 +++
 .../core/location/TestPortSupplierLocation.java |   2 +-
 .../core/mgmt/rebind/RebindFeedTest.java        |  16 +-
 .../feed/function/FunctionFeedTest.java         | 315 ++++++++
 .../feed/http/HttpFeedIntegrationTest.java      | 160 ++++
 .../apache/brooklyn/feed/http/HttpFeedTest.java | 392 ++++++++++
 .../feed/http/HttpValueFunctionsTest.java       |  94 +++
 .../brooklyn/feed/http/JsonFunctionsTest.java   | 130 ++++
 .../feed/shell/ShellFeedIntegrationTest.java    | 226 ++++++
 .../feed/ssh/SshFeedIntegrationTest.java        | 264 +++++++
 .../WindowsPerformanceCounterFeedLiveTest.java  | 104 +++
 .../WindowsPerformanceCounterFeedTest.java      | 132 ++++
 .../sensor/feed/ConfigToAttributesTest.java     |  70 --
 .../apache/brooklyn/sensor/feed/PollerTest.java | 108 ---
 .../sensor/feed/function/FunctionFeedTest.java  | 315 --------
 .../feed/http/HttpFeedIntegrationTest.java      | 160 ----
 .../brooklyn/sensor/feed/http/HttpFeedTest.java | 392 ----------
 .../feed/http/HttpValueFunctionsTest.java       |  94 ---
 .../sensor/feed/http/JsonFunctionsTest.java     | 130 ----
 .../feed/shell/ShellFeedIntegrationTest.java    | 226 ------
 .../sensor/feed/ssh/SshFeedIntegrationTest.java | 264 -------
 .../WindowsPerformanceCounterFeedLiveTest.java  | 104 ---
 .../WindowsPerformanceCounterFeedTest.java      | 132 ----
 .../policy/enricher/HttpLatencyDetector.java    |   6 +-
 .../entity/database/derby/DerbyDatabase.java    |   2 +-
 .../entity/database/derby/DerbySchema.java      |   6 +-
 .../postgresql/PostgreSqlNodeSaltImpl.java      |   4 +-
 .../entity/salt/SaltStackMasterImpl.java        |   3 +-
 .../entity/monitoring/zabbix/ZabbixFeed.java    |  10 +-
 .../monitoring/zabbix/ZabbixPollConfig.java     |   6 +-
 .../monitoring/zabbix/ZabbixServerImpl.java     |   6 +-
 .../nosql/hazelcast/HazelcastNodeImpl.java      |   6 +-
 .../brooklynnode/BrooklynClusterImpl.java       |   4 +-
 .../brooklynnode/BrooklynEntityMirrorImpl.java  |   4 +-
 .../entity/brooklynnode/BrooklynNodeImpl.java   |  10 +-
 .../SetHighAvailabilityModeEffectorBody.java    |   4 +-
 .../brooklyn/entity/chef/ChefAttributeFeed.java |   8 +-
 .../entity/chef/ChefAttributePollConfig.java    |   2 +-
 .../brooklyn/entity/java/JavaAppUtils.java      |   6 +-
 .../entity/java/JmxAttributeSensor.java         |   6 +-
 .../apache/brooklyn/entity/java/JmxSupport.java |   2 +-
 .../entity/java/VanillaJavaAppImpl.java         |   2 +-
 .../entity/machine/MachineEntityImpl.java       |   6 +-
 .../base/AbstractSoftwareProcessSshDriver.java  |   2 +-
 .../software/base/SoftwareProcessImpl.java      |   4 +-
 .../MachineLifecycleEffectorTasks.java          |   2 +-
 .../feed/jmx/JmxAttributePollConfig.java        |  74 ++
 .../org/apache/brooklyn/feed/jmx/JmxFeed.java   | 423 +++++++++++
 .../org/apache/brooklyn/feed/jmx/JmxHelper.java | 724 +++++++++++++++++++
 .../feed/jmx/JmxNotificationFilters.java        |  64 ++
 .../jmx/JmxNotificationSubscriptionConfig.java  |  95 +++
 .../feed/jmx/JmxOperationPollConfig.java        | 121 ++++
 .../brooklyn/feed/jmx/JmxValueFunctions.java    |  95 +++
 .../sensor/feed/jmx/JmxAttributePollConfig.java |  74 --
 .../brooklyn/sensor/feed/jmx/JmxFeed.java       | 423 -----------
 .../brooklyn/sensor/feed/jmx/JmxHelper.java     | 724 -------------------
 .../sensor/feed/jmx/JmxNotificationFilters.java |  64 --
 .../jmx/JmxNotificationSubscriptionConfig.java  |  95 ---
 .../sensor/feed/jmx/JmxOperationPollConfig.java | 121 ----
 .../sensor/feed/jmx/JmxValueFunctions.java      |  95 ---
 .../brooklyn/sensor/ssh/SshCommandSensor.java   |   6 +-
 .../winrm/WindowsPerformanceCounterSensors.java |   2 +-
 .../BrooklynNodeIntegrationTest.java            |   2 +-
 .../entity/brooklynnode/BrooklynNodeTest.java   |   2 +-
 .../brooklynnode/SameBrooklynNodeImpl.java      |   6 +-
 .../brooklynnode/SelectMasterEffectorTest.java  |   6 +-
 .../mysql/ChefSoloDriverToyMySqlEntity.java     |   4 +-
 .../brooklyn/entity/java/EntityPollingTest.java |   4 +-
 .../entity/java/VanillaJavaAppTest.java         |   2 +-
 .../base/lifecycle/ScriptHelperTest.java        |   4 +-
 .../software/base/test/jmx/JmxService.java      |   2 +-
 .../apache/brooklyn/feed/jmx/JmxFeedTest.java   | 422 +++++++++++
 .../apache/brooklyn/feed/jmx/JmxHelperTest.java | 311 ++++++++
 .../brooklyn/feed/jmx/RebindJmxFeedTest.java    | 148 ++++
 .../brooklyn/sensor/feed/jmx/JmxFeedTest.java   | 422 -----------
 .../brooklyn/sensor/feed/jmx/JmxHelperTest.java | 311 --------
 .../sensor/feed/jmx/RebindJmxFeedTest.java      | 148 ----
 .../entity/database/crate/CrateNodeImpl.java    |   8 +-
 .../database/mariadb/MariaDbNodeImpl.java       |   6 +-
 .../entity/database/mysql/MySqlClusterImpl.java |   4 +-
 .../entity/database/mysql/MySqlNodeImpl.java    |   6 +-
 .../PostgreSqlNodeChefImplFromScratch.java      |   4 +-
 .../messaging/activemq/ActiveMQBrokerImpl.java  |   4 +-
 .../activemq/ActiveMQDestinationImpl.java       |   4 +-
 .../messaging/activemq/ActiveMQQueueImpl.java   |   4 +-
 .../entity/messaging/kafka/KafkaBrokerImpl.java |   6 +-
 .../messaging/kafka/KafkaClusterImpl.java       |   2 +-
 .../entity/messaging/qpid/QpidBrokerImpl.java   |   6 +-
 .../messaging/qpid/QpidDestinationImpl.java     |   4 +-
 .../entity/messaging/qpid/QpidQueueImpl.java    |   4 +-
 .../entity/messaging/rabbit/RabbitQueue.java    |   6 +-
 .../entity/messaging/storm/StormImpl.java       |   4 +-
 .../entity/zookeeper/AbstractZooKeeperImpl.java |   6 +-
 .../entity/monitoring/monit/MonitNodeImpl.java  |   6 +-
 .../nosql/cassandra/CassandraNodeImpl.java      |  12 +-
 .../nosql/couchbase/CouchbaseClusterImpl.java   |   8 +-
 .../nosql/couchbase/CouchbaseNodeImpl.java      |   8 +-
 .../nosql/couchbase/CouchbaseNodeSshDriver.java |   2 +-
 .../couchbase/CouchbaseSyncGatewayImpl.java     |   6 +-
 .../entity/nosql/couchdb/CouchDBNodeImpl.java   |   6 +-
 .../elasticsearch/ElasticSearchNodeImpl.java    |   8 +-
 .../entity/nosql/mongodb/MongoDBServerImpl.java |   4 +-
 .../mongodb/sharding/MongoDBRouterImpl.java     |   4 +-
 .../entity/nosql/redis/RedisStoreImpl.java      |   8 +-
 .../entity/nosql/riak/RiakNodeImpl.java         |   6 +-
 .../entity/nosql/solr/SolrServerImpl.java       |   6 +-
 .../ElasticSearchClusterIntegrationTest.java    |   2 +-
 .../ElasticSearchNodeIntegrationTest.java       |   2 +-
 .../entity/osgi/karaf/KarafContainerImpl.java   |  10 +-
 .../entity/proxy/AbstractControllerImpl.java    |   2 +-
 .../AbstractNonProvisionedControllerImpl.java   |   2 +-
 .../entity/proxy/nginx/NginxControllerImpl.java |   8 +-
 .../ControlledDynamicWebAppClusterImpl.java     |   2 +-
 .../entity/webapp/jboss/JBoss6ServerImpl.java   |   4 +-
 .../entity/webapp/jboss/JBoss7ServerImpl.java   |   6 +-
 .../entity/webapp/jetty/Jetty6ServerImpl.java   |   4 +-
 .../webapp/nodejs/NodeJsWebAppServiceImpl.java  |   8 +-
 .../entity/webapp/tomcat/TomcatServerImpl.java  |   4 +-
 .../qa/load/SimulatedJBoss7ServerImpl.java      |  10 +-
 .../qa/load/SimulatedMySqlNodeImpl.java         |   4 +-
 .../qa/load/SimulatedNginxControllerImpl.java   |  10 +-
 .../brooklynnode/DeployBlueprintTest.java       |   2 +-
 181 files changed, 8717 insertions(+), 8718 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java b/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
index 994961c..0ec5903 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
@@ -63,6 +63,8 @@ import org.apache.brooklyn.core.entity.internal.EntityConfigMap;
 import org.apache.brooklyn.core.entity.lifecycle.PolicyDescriptor;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceNotUpLogic;
+import org.apache.brooklyn.core.feed.AbstractFeed;
+import org.apache.brooklyn.core.feed.ConfigToAttributes;
 import org.apache.brooklyn.core.internal.BrooklynInitialization;
 import org.apache.brooklyn.core.internal.storage.BrooklynStorage;
 import org.apache.brooklyn.core.internal.storage.Reference;
@@ -82,8 +84,6 @@ import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
 import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
 import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
-import org.apache.brooklyn.sensor.feed.AbstractFeed;
-import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/core/feed/AbstractFeed.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/feed/AbstractFeed.java b/core/src/main/java/org/apache/brooklyn/core/feed/AbstractFeed.java
new file mode 100644
index 0000000..a31b73e
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/feed/AbstractFeed.java
@@ -0,0 +1,240 @@
+/*
+ * 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.core.feed;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Collection;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.mgmt.rebind.RebindSupport;
+import org.apache.brooklyn.api.mgmt.rebind.mementos.FeedMemento;
+import org.apache.brooklyn.api.sensor.Feed;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.BrooklynFeatureEnablement;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.mgmt.rebind.BasicFeedRebindSupport;
+import org.apache.brooklyn.core.objs.AbstractEntityAdjunct;
+import org.apache.brooklyn.util.javalang.JavaClassNames;
+import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** 
+ * Captures common fields and processes for sensor feeds.
+ * These generally poll or subscribe to get sensor values for an entity.
+ * They make it easy to poll over http, jmx, etc.
+ */
+public abstract class AbstractFeed extends AbstractEntityAdjunct implements Feed {
+
+    private static final Logger log = LoggerFactory.getLogger(AbstractFeed.class);
+
+    public static final ConfigKey<Boolean> ONLY_IF_SERVICE_UP = ConfigKeys.newBooleanConfigKey("feed.onlyIfServiceUp", "", false);
+    
+    private final Object pollerStateMutex = new Object();
+    private transient volatile Poller<?> poller;
+    private transient volatile boolean activated;
+    private transient volatile boolean suspended;
+
+    public AbstractFeed() {
+    }
+    
+    /**
+     * @deprecated since 0.7.0; use no-arg constructor; call {@link #setEntity(EntityLocal)}
+     */
+    @Deprecated
+    public AbstractFeed(EntityLocal entity) {
+        this(entity, false);
+    }
+    
+    /**
+     * @deprecated since 0.7.0; use no-arg constructor; call {@link #setEntity(EntityLocal)} and {@code setConfig(ONLY_IF_SERVICE_UP, onlyIfServiceUp)}
+     */
+    @Deprecated
+    public AbstractFeed(EntityLocal entity, boolean onlyIfServiceUp) {
+        this.entity = checkNotNull(entity, "entity");
+        setConfig(ONLY_IF_SERVICE_UP, onlyIfServiceUp);
+    }
+
+    // Ensure idempotent, as called in builders (in case not registered with entity), and also called
+    // when registering with entity
+    @Override
+    public void setEntity(EntityLocal entity) {
+        super.setEntity(entity);
+        if (BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_FEED_REGISTRATION_PROPERTY)) {
+            ((EntityInternal)entity).feeds().addFeed(this);
+        }
+    }
+
+    protected void initUniqueTag(String uniqueTag, Object ...valsForDefault) {
+        if (Strings.isNonBlank(uniqueTag)) this.uniqueTag = uniqueTag;
+        else this.uniqueTag = getDefaultUniqueTag(valsForDefault);
+    }
+
+    protected String getDefaultUniqueTag(Object ...valsForDefault) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(JavaClassNames.simpleClassName(this));
+        if (valsForDefault.length==0) {
+            sb.append("@");
+            sb.append(hashCode());
+        } else if (valsForDefault.length==1 && valsForDefault[0] instanceof Collection){
+            sb.append(Strings.toUniqueString(valsForDefault[0], 80));
+        } else {
+            sb.append("[");
+            boolean first = true;
+            for (Object x: valsForDefault) {
+                if (!first) sb.append(";");
+                else first = false;
+                sb.append(Strings.toUniqueString(x, 80));
+            }
+            sb.append("]");
+        }
+        return sb.toString(); 
+    }
+
+    @Override
+    public void start() {
+        if (log.isDebugEnabled()) log.debug("Starting feed {} for {}", this, entity);
+        if (activated) { 
+            throw new IllegalStateException(String.format("Attempt to start feed %s of entity %s when already running", 
+                    this, entity));
+        }
+        if (poller != null) {
+            throw new IllegalStateException(String.format("Attempt to re-start feed %s of entity %s", this, entity));
+        }
+        
+        poller = new Poller<Object>(entity, getConfig(ONLY_IF_SERVICE_UP));
+        activated = true;
+        preStart();
+        synchronized (pollerStateMutex) {
+            // don't start poller if we are suspended
+            if (!suspended) {
+                poller.start();
+            }
+        }
+    }
+
+    @Override
+    public void suspend() {
+        synchronized (pollerStateMutex) {
+            if (activated && !suspended) {
+                poller.stop();
+            }
+            suspended = true;
+        }
+    }
+    
+    @Override
+    public void resume() {
+        synchronized (pollerStateMutex) {
+            if (activated && suspended) {
+                poller.start();
+            }
+            suspended = false;
+        }
+    }
+    
+    @Override
+    public void destroy() {
+        stop();
+    }
+
+    @Override
+    public void stop() {
+        if (!activated) { 
+            log.debug("Ignoring attempt to stop feed {} of entity {} when not running", this, entity);
+            return;
+        }
+        if (log.isDebugEnabled()) log.debug("stopping feed {} for {}", this, entity);
+        
+        activated = false;
+        preStop();
+        synchronized (pollerStateMutex) {
+            if (!suspended) {
+                poller.stop();
+            }
+        }
+        postStop();
+        super.destroy();
+    }
+
+    @Override
+    public boolean isActivated() {
+        return activated;
+    }
+    
+    public EntityLocal getEntity() {
+        return entity;
+    }
+    
+    protected boolean isConnected() {
+        // TODO Default impl will result in multiple logs for same error if becomes unreachable
+        // (e.g. if ssh gets NoRouteToHostException, then every AttributePollHandler for that
+        // feed will log.warn - so if polling for 10 sensors/attributes will get 10 log messages).
+        // Would be nice if reduced this logging duplication.
+        // (You can reduce it by providing a better 'isConnected' implementation of course.)
+        return isRunning() && entity!=null && !((EntityInternal)entity).getManagementSupport().isNoLongerManaged();
+    }
+
+    @Override
+    public boolean isSuspended() {
+        return suspended;
+    }
+
+    @Override
+    public boolean isRunning() {
+        return isActivated() && !isSuspended() && !isDestroyed() && getPoller()!=null && getPoller().isRunning();
+    }
+
+    @Override
+    public RebindSupport<FeedMemento> getRebindSupport() {
+        return new BasicFeedRebindSupport(this);
+    }
+
+    @Override
+    protected void onChanged() {
+        // TODO Auto-generated method stub
+    }
+
+    /**
+     * For overriding.
+     */
+    protected void preStart() {
+    }
+    
+    /**
+     * For overriding.
+     */
+    protected void preStop() {
+    }
+    
+    /**
+     * For overriding.
+     */
+    protected void postStop() {
+    }
+    
+    /**
+     * For overriding, where sub-class can change return-type generics!
+     */
+    protected Poller<?> getPoller() {
+        return poller;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/core/feed/AttributePollHandler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/feed/AttributePollHandler.java b/core/src/main/java/org/apache/brooklyn/core/feed/AttributePollHandler.java
new file mode 100644
index 0000000..c266836
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/feed/AttributePollHandler.java
@@ -0,0 +1,248 @@
+/*
+ * 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.core.feed;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle.Transition;
+import org.apache.brooklyn.util.core.flags.TypeCoercions;
+import org.apache.brooklyn.util.core.task.Tasks;
+import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Objects;
+
+/**
+ * Handler for when polling an entity's attribute. On each poll result the entity's attribute is set.
+ * 
+ * Calls to onSuccess and onError will happen sequentially, but may be called from different threads 
+ * each time. Note that no guarantees of a synchronized block exist, so additional synchronization 
+ * would be required for the Java memory model's "happens before" relationship.
+ * 
+ * @author aled
+ */
+public class AttributePollHandler<V> implements PollHandler<V> {
+
+    public static final Logger log = LoggerFactory.getLogger(AttributePollHandler.class);
+
+    private final FeedConfig<V,?,?> config;
+    private final EntityLocal entity;
+    @SuppressWarnings("rawtypes")
+    private final AttributeSensor sensor;
+    private final AbstractFeed feed;
+    private final boolean suppressDuplicates;
+    
+    // allow 30 seconds before logging at WARN, if there has been no success yet;
+    // after success WARN immediately
+    // TODO these should both be configurable
+    private Duration logWarningGraceTimeOnStartup = Duration.THIRTY_SECONDS;
+    private Duration logWarningGraceTime = Duration.millis(0);
+    
+    // internal state to look after whether to log warnings
+    private volatile Long lastSuccessTime = null;
+    private volatile Long currentProblemStartTime = null;
+    private volatile boolean currentProblemLoggedAsWarning = false;
+    private volatile boolean lastWasProblem = false;
+
+    
+    public AttributePollHandler(FeedConfig<V,?,?> config, EntityLocal entity, AbstractFeed feed) {
+        this.config = checkNotNull(config, "config");
+        this.entity = checkNotNull(entity, "entity");
+        this.sensor = checkNotNull(config.getSensor(), "sensor");
+        this.feed = checkNotNull(feed, "feed");
+        this.suppressDuplicates = config.getSupressDuplicates();
+    }
+
+    @Override
+    public boolean checkSuccess(V val) {
+        // Always true if no checkSuccess predicate was configured.
+        return !config.hasCheckSuccessHandler() || config.getCheckSuccess().apply(val);
+    }
+
+    @Override
+    public void onSuccess(V val) {
+        if (lastWasProblem) {
+            if (currentProblemLoggedAsWarning) { 
+                log.info("Success (following previous problem) reading "+getBriefDescription());
+            } else {
+                log.debug("Success (following previous problem) reading "+getBriefDescription());
+            }
+            lastWasProblem = false;
+            currentProblemStartTime = null;
+            currentProblemLoggedAsWarning = false;
+        }
+        lastSuccessTime = System.currentTimeMillis();
+        if (log.isTraceEnabled()) log.trace("poll for {} got: {}", new Object[] {getBriefDescription(), val});
+        
+        try {
+            setSensor(transformValueOnSuccess(val));
+        } catch (Exception e) {
+            if (feed.isConnected()) {
+                log.warn("unable to compute "+getBriefDescription()+"; on val="+val, e);
+            } else {
+                if (log.isDebugEnabled()) log.debug("unable to compute "+getBriefDescription()+"; val="+val+" (when inactive)", e);
+            }
+        }
+    }
+
+    /** allows post-processing, such as applying a success handler; 
+     * default applies the onSuccess handler (which is recommended) */
+    protected Object transformValueOnSuccess(V val) {
+        return config.hasSuccessHandler() ? config.getOnSuccess().apply(val) : val;
+    }
+
+    @Override
+    public void onFailure(V val) {
+        if (!config.hasFailureHandler()) {
+            onException(new Exception("checkSuccess of "+this+" for "+getBriefDescription()+" was false but poller has no failure handler"));
+        } else {
+            logProblem("failure", val);
+
+            try {
+                setSensor(config.hasFailureHandler() ? config.getOnFailure().apply((V)val) : val);
+            } catch (Exception e) {
+                if (feed.isConnected()) {
+                    log.warn("Error computing " + getBriefDescription() + "; val=" + val+": "+ e, e);
+                } else {
+                    if (log.isDebugEnabled())
+                        log.debug("Error computing " + getBriefDescription() + "; val=" + val + " (when inactive)", e);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onException(Exception exception) {
+        if (!feed.isConnected()) {
+            if (log.isTraceEnabled()) log.trace("Read of {} in {} gave exception (while not connected or not yet connected): {}", new Object[] {this, getBriefDescription(), exception});
+        } else {
+            logProblem("exception", exception);
+        }
+
+        if (config.hasExceptionHandler()) {
+            try {
+                setSensor( config.getOnException().apply(exception) );
+            } catch (Exception e) {
+                if (feed.isConnected()) {
+                    log.warn("unable to compute "+getBriefDescription()+"; on exception="+exception, e);
+                } else {
+                    if (log.isDebugEnabled()) log.debug("unable to compute "+getBriefDescription()+"; exception="+exception+" (when inactive)", e);
+                }
+            }
+        }
+    }
+
+    protected void logProblem(String type, Object val) {
+        if (lastWasProblem && currentProblemLoggedAsWarning) {
+            if (log.isTraceEnabled())
+                log.trace("Recurring {} reading {} in {}: {}", new Object[] {type, this, getBriefDescription(), val});
+        } else {
+            long nowTime = System.currentTimeMillis();
+            // get a non-volatile value
+            Long currentProblemStartTimeCache = currentProblemStartTime;
+            long expiryTime = 
+                    (lastSuccessTime!=null && !isTransitioningOrStopped()) ? lastSuccessTime+logWarningGraceTime.toMilliseconds() :
+                    currentProblemStartTimeCache!=null ? currentProblemStartTimeCache+logWarningGraceTimeOnStartup.toMilliseconds() :
+                    nowTime+logWarningGraceTimeOnStartup.toMilliseconds();
+            if (!lastWasProblem) {
+                if (expiryTime <= nowTime) {
+                    currentProblemLoggedAsWarning = true;
+                    if (entity==null || !Entities.isNoLongerManaged(entity)) {
+                        log.warn("Read of " + getBriefDescription() + " gave " + type + ": " + val);
+                    } else {
+                        log.debug("Read of " + getBriefDescription() + " gave " + type + ": " + val);
+                    }
+                    if (log.isDebugEnabled() && val instanceof Throwable)
+                        log.debug("Trace for "+type+" reading "+getBriefDescription()+": "+val, (Throwable)val);
+                } else {
+                    if (log.isDebugEnabled())
+                        log.debug("Read of " + getBriefDescription() + " gave " + type + " (in grace period): " + val);
+                }
+                lastWasProblem = true;
+                currentProblemStartTime = nowTime;
+            } else {
+                if (expiryTime <= nowTime) {
+                    currentProblemLoggedAsWarning = true;
+                    log.warn("Read of " + getBriefDescription() + " gave " + type + 
+                            " (grace period expired, occurring for "+Duration.millis(nowTime - currentProblemStartTimeCache)+
+                            (config.hasExceptionHandler() ? "" : ", no exception handler set for sensor")+
+                            ")"+
+                            ": " + val);
+                    if (log.isDebugEnabled() && val instanceof Throwable)
+                        log.debug("Trace for "+type+" reading "+getBriefDescription()+": "+val, (Throwable)val);
+                } else {
+                    if (log.isDebugEnabled()) 
+                        log.debug("Recurring {} reading {} in {} (still in grace period): {}", new Object[] {type, this, getBriefDescription(), val});
+                }
+            }
+        }
+    }
+
+    protected boolean isTransitioningOrStopped() {
+        if (entity==null) return false;
+        Transition expected = entity.getAttribute(Attributes.SERVICE_STATE_EXPECTED);
+        if (expected==null) return false;
+        return (expected.getState()==Lifecycle.STARTING || expected.getState()==Lifecycle.STOPPING || expected.getState()==Lifecycle.STOPPED);
+    }
+
+    @SuppressWarnings("unchecked")
+    protected void setSensor(Object v) {
+        if (Entities.isNoLongerManaged(entity)) {
+            if (Tasks.isInterrupted()) return;
+            log.warn(""+entity+" is not managed; feed "+this+" setting "+sensor+" to "+v+" at this time is not supported ("+Tasks.current()+")");
+        }
+        
+        if (v == FeedConfig.UNCHANGED) {
+            // nothing
+        } else if (v == FeedConfig.REMOVE) {
+            ((EntityInternal)entity).removeAttribute(sensor);
+        } else if (sensor == FeedConfig.NO_SENSOR) {
+            // nothing
+        } else {
+            Object coercedV = TypeCoercions.coerce(v, sensor.getType());
+            if (suppressDuplicates && Objects.equal(coercedV, entity.getAttribute(sensor))) {
+                // no change; nothing
+            } else {
+                entity.setAttribute(sensor, coercedV);
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        return super.toString()+"["+getDescription()+"]";
+    }
+    
+    @Override
+    public String getDescription() {
+        return sensor.getName()+" @ "+entity.getId()+" <- "+config;
+    }
+    
+    protected String getBriefDescription() {
+        return ""+entity+"->"+(sensor==FeedConfig.NO_SENSOR ? "(dynamic sensors)" : ""+sensor);
+    }
+        
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/core/feed/ConfigToAttributes.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/feed/ConfigToAttributes.java b/core/src/main/java/org/apache/brooklyn/core/feed/ConfigToAttributes.java
new file mode 100644
index 0000000..d455e80
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/feed/ConfigToAttributes.java
@@ -0,0 +1,59 @@
+/*
+ * 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.core.feed;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.TemplatedStringAttributeSensorAndConfigKey;
+
+
+/** Simple config adapter for setting {@link AttributeSensorAndConfigKey} sensor values from the config value or config default */ 
+public class ConfigToAttributes {
+
+    //normally just applied once, statically, not registered...
+    public static void apply(EntityLocal entity) {
+        for (Sensor<?> it : entity.getEntityType().getSensors()) {
+            if (it instanceof AttributeSensorAndConfigKey) {
+                apply(entity, (AttributeSensorAndConfigKey<?,?>)it);
+            }
+        }
+    }
+
+    /**
+     * Convenience for ensuring an individual sensor is set from its config key
+     * (e.g. sub-classes of DynamicWebAppCluster that don't want to set HTTP_PORT etc!)
+     */
+    public static <T> T apply(EntityLocal entity, AttributeSensorAndConfigKey<?,T> key) {
+        T v = entity.getAttribute(key);
+        if (v!=null) return v;
+        v = key.getAsSensorValue(entity);
+        if (v!=null) entity.setAttribute(key, v);
+        return v;
+    }
+
+    /**
+     * Convenience for transforming a config value (e.g. processing a {@link TemplatedStringAttributeSensorAndConfigKey}),
+     * outside of the context of an entity.
+     */
+    public static <T> T transform(ManagementContext managementContext, AttributeSensorAndConfigKey<?,T> key) {
+        return key.getAsSensorValue(managementContext);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/core/feed/DelegatingPollHandler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/feed/DelegatingPollHandler.java b/core/src/main/java/org/apache/brooklyn/core/feed/DelegatingPollHandler.java
new file mode 100644
index 0000000..fae7dd6
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/feed/DelegatingPollHandler.java
@@ -0,0 +1,96 @@
+/*
+ * 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.core.feed;
+
+import java.util.List;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * A poll handler that delegates each call to a set of poll handlers.
+ * 
+ * @author aled
+ */
+public class DelegatingPollHandler<V> implements PollHandler<V> {
+
+    private final List<AttributePollHandler<? super V>> delegates;
+
+    public DelegatingPollHandler(Iterable<AttributePollHandler<? super V>> delegates) {
+        super();
+        this.delegates = ImmutableList.copyOf(delegates);
+    }
+
+    @Override
+    public boolean checkSuccess(V val) {
+        for (AttributePollHandler<? super V> delegate : delegates) {
+            if (!delegate.checkSuccess(val))
+                return false;
+        }
+        return true;
+    }
+
+    @Override
+    public void onSuccess(V val) {
+        for (AttributePollHandler<? super V> delegate : delegates) {
+            delegate.onSuccess(val);
+        }
+    }
+
+    @Override
+    public void onFailure(V val) {
+        for (AttributePollHandler<? super V> delegate : delegates) {
+            delegate.onFailure(val);
+        }
+    }
+
+    @Override
+    public void onException(Exception exception) {
+        for (AttributePollHandler<? super V> delegate : delegates) {
+            delegate.onException(exception);
+        }
+    }
+    
+    @Override
+    public String toString() {
+        return super.toString()+"["+getDescription()+"]";
+    }
+    
+    @Override
+    public String getDescription() {
+        if (delegates.isEmpty())
+            return "(empty delegate list)";
+        if (delegates.size()==1) 
+            return delegates.get(0).getDescription();
+        StringBuilder sb = new StringBuilder();
+        sb.append("[");
+        int count = 0;
+        for (AttributePollHandler<? super V> delegate : delegates) {
+            if (count>0) sb.append("; ");
+            sb.append(delegate.getDescription());
+            if (count>2) {
+                sb.append("; ...");
+                break;
+            }
+            count++;
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/core/feed/FeedConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/feed/FeedConfig.java b/core/src/main/java/org/apache/brooklyn/core/feed/FeedConfig.java
new file mode 100644
index 0000000..4d06680
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/feed/FeedConfig.java
@@ -0,0 +1,297 @@
+/*
+ * 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.core.feed;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.guava.Functionals;
+import org.apache.brooklyn.util.javalang.JavaClassNames;
+import org.apache.brooklyn.util.text.Strings;
+
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.base.Objects;
+import com.google.common.base.Predicate;
+
+/**
+ * Configuration for a poll, or a subscription etc, that is being added to a feed.
+ * 
+ * @author aled
+ */
+public class FeedConfig<V, T, F extends FeedConfig<V, T, F>> {
+
+    /** The onSuccess or onError functions can return this value to indicate that the sensor should not change. 
+     * @deprecated since 0.7.0 use UNCHANGED */
+    public static final Object UNSET = Entities.UNCHANGED;
+    /** The onSuccess or onError functions can return this value to indicate that the sensor should not change. */ 
+    public static final Object UNCHANGED = Entities.UNCHANGED;
+    /** The onSuccess or onError functions can return this value to indicate that the sensor value should be removed
+     * (cf 'null', but useful in dynamic situations) */ 
+    public static final Object REMOVE = Entities.REMOVE;
+    
+    /** Indicates that no sensor is being used here. This sensor is suppressed,
+     * but is useful where you want to use the feeds with custom success/exception/failure functions
+     * which directly set multiple sensors, e.g. dynamically based on the poll response.
+     * <p>
+     * See {@link HttpPollConfig#forMultiple()} and its usages.
+     * (It can work for any poll config, but conveniences have not been supplied for others.)  */
+    public static final AttributeSensor<Void> NO_SENSOR = Sensors.newSensor(Void.class, "brooklyn.no.sensor");
+    
+    private final AttributeSensor<T> sensor;
+    private Function<? super V, T> onsuccess;
+    private Function<? super V, T> onfailure;
+    private Function<? super Exception, T> onexception;
+    private Predicate<? super V> checkSuccess;
+    private boolean suppressDuplicates;
+    private boolean enabled = true;
+    
+    public FeedConfig(AttributeSensor<T> sensor) {
+        this.sensor = checkNotNull(sensor, "sensor");
+    }
+
+    public FeedConfig(FeedConfig<V, T, F> other) {
+        this.sensor = other.sensor;
+        this.onsuccess = other.onsuccess;
+        this.onfailure = other.onfailure;
+        this.onexception = other.onexception;
+        this.checkSuccess = other.checkSuccess;
+        this.suppressDuplicates = other.suppressDuplicates;
+        this.enabled = other.enabled;
+    }
+
+    @SuppressWarnings("unchecked")
+    protected F self() {
+        return (F) this;
+    }
+    
+    public AttributeSensor<T> getSensor() {
+        return sensor;
+    }
+
+    public Predicate<? super V> getCheckSuccess() {
+        return checkSuccess;
+    }
+    
+    public Function<? super V, T> getOnSuccess() {
+        return onsuccess;
+    }
+
+    public Function<? super V, T> getOnFailure() {
+        return onfailure;
+    }
+    
+    public Function<? super Exception, T> getOnException() {
+        return onexception;
+    }
+
+    public boolean getSupressDuplicates() {
+        return suppressDuplicates;
+    }
+    
+    public boolean isEnabled() {
+        return enabled;
+    }
+    
+    /** sets the predicate used to check whether a feed run is successful */
+    public F checkSuccess(Predicate<? super V> val) {
+        this.checkSuccess = checkNotNull(val, "checkSuccess");
+        return self();
+    }
+    /** as {@link #checkSuccess(Predicate)} */
+    public F checkSuccess(final Function<? super V,Boolean> val) {
+        return checkSuccess(Functionals.predicate(val));
+    }
+    @SuppressWarnings("unused")
+    /** @deprecated since 0.7.0, kept for rebind */ @Deprecated
+    private F checkSuccessLegacy(final Function<? super V,Boolean> val) {
+        return checkSuccess(new Predicate<V>() {
+            @Override
+            public boolean apply(V input) {
+                return val.apply(input);
+            }
+        });
+    }
+
+    public F onSuccess(Function<? super V,T> val) {
+        this.onsuccess = checkNotNull(val, "onSuccess");
+        return self();
+    }
+    
+    public F setOnSuccess(T val) {
+        return onSuccess(Functions.constant(val));
+    }
+    
+    /** a failure is when the connection is fine (no exception) but the other end returns a result object V 
+     * which the feed can tell indicates a failure (e.g. HTTP code 404) */
+    public F onFailure(Function<? super V,T> val) {
+        this.onfailure = checkNotNull(val, "onFailure");
+        return self();
+    }
+
+    public F setOnFailure(T val) {
+        return onFailure(Functions.constant(val));
+    }
+
+    /** registers a callback to be used {@link #onSuccess(Function)} and {@link #onFailure(Function)}, 
+     * i.e. whenever a result comes back, but not in case of exceptions being thrown (ie problems communicating) */
+    public F onResult(Function<? super V, T> val) {
+        onSuccess(val);
+        return onFailure(val);
+    }
+
+    public F setOnResult(T val) {
+        return onResult(Functions.constant(val));
+    }
+
+    /** an exception is when there is an error in the communication */
+    public F onException(Function<? super Exception,T> val) {
+        this.onexception = checkNotNull(val, "onException");
+        return self();
+    }
+    
+    public F setOnException(T val) {
+        return onException(Functions.constant(val));
+    }
+
+    /** convenience for indicating a behaviour to occur for both
+     * {@link #onException(Function)}
+     * (error connecting) and 
+     * {@link #onFailure(Function)} 
+     * (successful communication but failure report from remote end) */
+    public F onFailureOrException(Function<Object,T> val) {
+        onFailure(val);
+        return onException(val);
+    }
+    
+    public F setOnFailureOrException(T val) {
+        return onFailureOrException(Functions.constant(val));
+    }
+
+    public F suppressDuplicates(boolean val) {
+        suppressDuplicates = val;
+        return self();
+    }
+    
+    /**
+     * Whether this feed is enabled (defaulting to true).
+     */
+    public F enabled(boolean val) {
+        enabled = val;
+        return self();
+    }
+    
+    public boolean hasSuccessHandler() {
+        return this.onsuccess != null;
+    }
+
+    public boolean hasFailureHandler() {
+        return this.onfailure != null;
+    }
+
+    public boolean hasExceptionHandler() {
+        return this.onexception != null;
+    }
+
+    public boolean hasCheckSuccessHandler() {
+        return this.checkSuccess != null;
+    }
+
+    
+    @Override
+    public String toString() {
+        StringBuilder result = new StringBuilder();
+        result.append(toStringBaseName());
+        result.append("[");
+        boolean contents = false;
+        Object source = toStringPollSource();
+        AttributeSensor<T> s = getSensor();
+        if (Strings.isNonBlank(Strings.toString(source))) {
+            result.append(Strings.toUniqueString(source, 40));
+            if (s!=null) {
+                result.append("->");
+                result.append(s.getName());
+            }
+            contents = true;
+        } else if (s!=null) {
+            result.append(s.getName());
+            contents = true;
+        }
+        MutableList<Object> fields = toStringOtherFields();
+        if (fields!=null) {
+            for (Object field: fields) {
+                if (Strings.isNonBlank(Strings.toString(field))) {
+                    if (contents) result.append(";");
+                    contents = true;
+                    result.append(field);
+                }
+            }
+        }
+        result.append("]");
+        return result.toString();
+    }
+
+    /** can be overridden to supply a simpler base name than the class name */
+    protected String toStringBaseName() {
+        return JavaClassNames.simpleClassName(this);
+    }
+    /** can be overridden to supply add'l info for the {@link #toString()}; subclasses can add to the returned value */
+    protected MutableList<Object> toStringOtherFields() {
+        return MutableList.<Object>of();
+    }
+    /** can be overridden to supply add'l info for the {@link #toString()}, placed before the sensor with -> */
+    protected Object toStringPollSource() {
+        return null;
+    }
+    /** all configs should supply a unique tag element, inserted into the feed */
+    protected String getUniqueTag() {
+        return toString();
+    }
+
+    /** returns fields which should be used for equality, including by default {@link #toStringOtherFields()} and {@link #toStringPollSource()};
+     * subclasses can add to the returned value */
+    protected MutableList<Object> equalsFields() {
+        MutableList<Object> result = MutableList.of().appendIfNotNull(getSensor()).appendIfNotNull(toStringPollSource());
+        for (Object field: toStringOtherFields()) result.appendIfNotNull(field);
+        return result;
+    }
+
+    @Override
+    public int hashCode() { 
+        int hc = super.hashCode();
+        for (Object f: equalsFields())
+            hc = Objects.hashCode(hc, f);
+        return hc;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (!super.equals(obj)) return false;
+        PollConfig<?,?,?> other = (PollConfig<?,?,?>) obj;
+        if (!Objects.equal(getUniqueTag(), other.getUniqueTag())) return false;
+        if (!Objects.equal(equalsFields(), other.equalsFields())) return false;
+        return true;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/core/feed/PollConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/feed/PollConfig.java b/core/src/main/java/org/apache/brooklyn/core/feed/PollConfig.java
new file mode 100644
index 0000000..133431b
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/feed/PollConfig.java
@@ -0,0 +1,85 @@
+/*
+ * 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.core.feed;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.time.Duration;
+
+/**
+ * Configuration for polling, which is being added to a feed (e.g. to poll a given URL over http).
+ * 
+ * @author aled
+ */
+public class PollConfig<V, T, F extends PollConfig<V, T, F>> extends FeedConfig<V, T, F> {
+
+    private long period = -1;
+    private String description;
+
+    public PollConfig(AttributeSensor<T> sensor) {
+        super(sensor);
+    }
+
+    public PollConfig(PollConfig<V,T,F> other) {
+        super(other);
+        this.period = other.period;
+    }
+
+    public long getPeriod() {
+        return period;
+    }
+    
+    public F period(Duration val) {
+        checkArgument(val.toMilliseconds() >= 0, "period must be greater than or equal to zero");
+        this.period = val.toMilliseconds();
+        return self();
+    }
+    
+    public F period(long val) {
+        checkArgument(val >= 0, "period must be greater than or equal to zero");
+        this.period = val; return self();
+    }
+    
+    public F period(long val, TimeUnit units) {
+        checkArgument(val >= 0, "period must be greater than or equal to zero");
+        return period(units.toMillis(val));
+    }
+    
+    public F description(String description) {
+        this.description = description;
+        return self();
+    }
+    
+    public String getDescription() {
+        return description;
+    }
+    
+    @Override protected MutableList<Object> toStringOtherFields() {
+        return super.toStringOtherFields().appendIfNotNull(description);
+    }
+
+    @Override
+    protected MutableList<Object> equalsFields() {
+        return super.equalsFields().appendIfNotNull(period);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/core/feed/PollHandler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/feed/PollHandler.java b/core/src/main/java/org/apache/brooklyn/core/feed/PollHandler.java
new file mode 100644
index 0000000..a63ebde
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/feed/PollHandler.java
@@ -0,0 +1,38 @@
+/*
+ * 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.core.feed;
+
+/**
+ * Notified by the Poller of the result for each job, on each poll.
+ * 
+ * @author aled
+ */
+public interface PollHandler<V> {
+
+    public boolean checkSuccess(V val);
+
+    public void onSuccess(V val);
+
+    public void onFailure(V val);
+
+    public void onException(Exception exception);
+
+    public String getDescription();
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/core/feed/Poller.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/feed/Poller.java b/core/src/main/java/org/apache/brooklyn/core/feed/Poller.java
new file mode 100644
index 0000000..fd50ebd
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/feed/Poller.java
@@ -0,0 +1,205 @@
+/*
+ * 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.core.feed;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.concurrent.Callable;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.task.DynamicSequentialTask;
+import org.apache.brooklyn.util.core.task.ScheduledTask;
+import org.apache.brooklyn.util.core.task.Tasks;
+import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Objects;
+
+
+/** 
+ * For executing periodic polls.
+ * Jobs are added to the schedule, and then the poller is started.
+ * The jobs will then be executed periodically, and the handler called for the result/failure.
+ * 
+ * Assumes the schedule+start will be done single threaded, and that stop will not be done concurrently.
+ */
+public class Poller<V> {
+    public static final Logger log = LoggerFactory.getLogger(Poller.class);
+
+    private final EntityLocal entity;
+    private final boolean onlyIfServiceUp;
+    private final Set<Callable<?>> oneOffJobs = new LinkedHashSet<Callable<?>>();
+    private final Set<PollJob<V>> pollJobs = new LinkedHashSet<PollJob<V>>();
+    private final Set<Task<?>> oneOffTasks = new LinkedHashSet<Task<?>>();
+    private final Set<ScheduledTask> tasks = new LinkedHashSet<ScheduledTask>();
+    private volatile boolean started = false;
+    
+    private static class PollJob<V> {
+        final PollHandler<? super V> handler;
+        final Duration pollPeriod;
+        final Runnable wrappedJob;
+        private boolean loggedPreviousException = false;
+        
+        PollJob(final Callable<V> job, final PollHandler<? super V> handler, Duration period) {
+            this.handler = handler;
+            this.pollPeriod = period;
+            
+            wrappedJob = new Runnable() {
+                public void run() {
+                    try {
+                        V val = job.call();
+                        loggedPreviousException = false;
+                        if (handler.checkSuccess(val)) {
+                            handler.onSuccess(val);
+                        } else {
+                            handler.onFailure(val);
+                        }
+                    } catch (Exception e) {
+                        if (loggedPreviousException) {
+                            if (log.isTraceEnabled()) log.trace("PollJob for {}, repeated consecutive failures, handling {} using {}", new Object[] {job, e, handler});
+                        } else {
+                            if (log.isDebugEnabled()) log.debug("PollJob for {} handling {} using {}", new Object[] {job, e, handler});
+                            loggedPreviousException = true;
+                        }
+                        handler.onException(e);
+                    }
+                }
+            };
+        }
+    }
+    
+    /** @deprecated since 0.7.0, pass in whether should run onlyIfServiceUp */
+    @Deprecated
+    public Poller(EntityLocal entity) {
+        this(entity, false);
+    }
+    public Poller(EntityLocal entity, boolean onlyIfServiceUp) {
+        this.entity = entity;
+        this.onlyIfServiceUp = onlyIfServiceUp;
+    }
+    
+    /** Submits a one-off poll job; recommended that callers supply to-String so that task has a decent description */
+    public void submit(Callable<?> job) {
+        if (started) {
+            throw new IllegalStateException("Cannot submit additional tasks after poller has started");
+        }
+        oneOffJobs.add(job);
+    }
+
+    public void scheduleAtFixedRate(Callable<V> job, PollHandler<? super V> handler, long period) {
+        scheduleAtFixedRate(job, handler, Duration.millis(period));
+    }
+    public void scheduleAtFixedRate(Callable<V> job, PollHandler<? super V> handler, Duration period) {
+        if (started) {
+            throw new IllegalStateException("Cannot schedule additional tasks after poller has started");
+        }
+        PollJob<V> foo = new PollJob<V>(job, handler, period);
+        pollJobs.add(foo);
+    }
+
+    @SuppressWarnings({ "unchecked" })
+    public void start() {
+        // TODO Previous incarnation of this logged this logged polledSensors.keySet(), but we don't know that anymore
+        // Is that ok, are can we do better?
+        
+        if (log.isDebugEnabled()) log.debug("Starting poll for {} (using {})", new Object[] {entity, this});
+        if (started) { 
+            throw new IllegalStateException(String.format("Attempt to start poller %s of entity %s when already running", 
+                    this, entity));
+        }
+        
+        started = true;
+        
+        for (final Callable<?> oneOffJob : oneOffJobs) {
+            Task<?> task = Tasks.builder().dynamic(false).body((Callable<Object>) oneOffJob).name("Poll").description("One-time poll job "+oneOffJob).build();
+            oneOffTasks.add(((EntityInternal)entity).getExecutionContext().submit(task));
+        }
+        
+        for (final PollJob<V> pollJob : pollJobs) {
+            final String scheduleName = pollJob.handler.getDescription();
+            if (pollJob.pollPeriod.compareTo(Duration.ZERO) > 0) {
+                Callable<Task<?>> pollingTaskFactory = new Callable<Task<?>>() {
+                    public Task<?> call() {
+                        DynamicSequentialTask<Void> task = new DynamicSequentialTask<Void>(MutableMap.of("displayName", scheduleName, "entity", entity), 
+                            new Callable<Void>() { public Void call() {
+                                if (onlyIfServiceUp && !Boolean.TRUE.equals(entity.getAttribute(Attributes.SERVICE_UP))) {
+                                        return null;
+                                }
+                                pollJob.wrappedJob.run();
+                                return null; 
+                            } } );
+                        BrooklynTaskTags.setTransient(task);
+                        return task;
+                    }
+                };
+                ScheduledTask task = new ScheduledTask(MutableMap.of("period", pollJob.pollPeriod, "displayName", "scheduled:"+scheduleName), pollingTaskFactory);
+                tasks.add((ScheduledTask)Entities.submit(entity, task));
+            } else {
+                if (log.isDebugEnabled()) log.debug("Activating poll (but leaving off, as period {}) for {} (using {})", new Object[] {pollJob.pollPeriod, entity, this});
+            }
+        }
+    }
+    
+    public void stop() {
+        if (log.isDebugEnabled()) log.debug("Stopping poll for {} (using {})", new Object[] {entity, this});
+        if (!started) { 
+            throw new IllegalStateException(String.format("Attempt to stop poller %s of entity %s when not running", 
+                    this, entity));
+        }
+        
+        started = false;
+        for (Task<?> task : oneOffTasks) {
+            if (task != null) task.cancel(true);
+        }
+        for (ScheduledTask task : tasks) {
+            if (task != null) task.cancel();
+        }
+        oneOffTasks.clear();
+        tasks.clear();
+    }
+
+    public boolean isRunning() {
+        boolean hasActiveTasks = false;
+        for (Task<?> task: tasks) {
+            if (task.isBegun() && !task.isDone()) {
+                hasActiveTasks = true;
+                break;
+            }
+        }
+        if (!started && hasActiveTasks) {
+            log.warn("Poller should not be running, but has active tasks, tasks: "+tasks);
+        }
+        return started && hasActiveTasks;
+    }
+    
+    protected boolean isEmpty() {
+        return pollJobs.isEmpty();
+    }
+    
+    public String toString() {
+        return Objects.toStringHelper(this).add("entity", entity).toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicEntityRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicEntityRebindSupport.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicEntityRebindSupport.java
index 2e4a971..2a5e92e 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicEntityRebindSupport.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicEntityRebindSupport.java
@@ -34,11 +34,11 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.feed.AbstractFeed;
 import org.apache.brooklyn.core.mgmt.rebind.dto.MementosGenerators;
 import org.apache.brooklyn.core.policy.AbstractPolicy;
 import org.apache.brooklyn.entity.group.AbstractGroupImpl;
 import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
-import org.apache.brooklyn.sensor.feed.AbstractFeed;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicFeedRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicFeedRebindSupport.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicFeedRebindSupport.java
index 479fbbf..4630be1 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicFeedRebindSupport.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicFeedRebindSupport.java
@@ -20,7 +20,7 @@ package org.apache.brooklyn.core.mgmt.rebind;
 
 import org.apache.brooklyn.api.mgmt.rebind.RebindContext;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.FeedMemento;
-import org.apache.brooklyn.sensor.feed.AbstractFeed;
+import org.apache.brooklyn.core.feed.AbstractFeed;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.flags.FlagUtils;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java
index c3e8030..e9478ef 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java
@@ -67,6 +67,7 @@ import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.entity.AbstractApplication;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.feed.AbstractFeed;
 import org.apache.brooklyn.core.location.AbstractLocation;
 import org.apache.brooklyn.core.location.internal.LocationInternal;
 import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
@@ -86,7 +87,6 @@ import org.apache.brooklyn.core.objs.proxy.InternalLocationFactory;
 import org.apache.brooklyn.core.objs.proxy.InternalPolicyFactory;
 import org.apache.brooklyn.core.policy.AbstractPolicy;
 import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
-import org.apache.brooklyn.sensor.feed.AbstractFeed;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.flags.FlagUtils;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
index 761341b..929b63c 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
@@ -51,6 +51,7 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.catalog.internal.CatalogItemDo;
 import org.apache.brooklyn.core.entity.EntityDynamicType;
 import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.feed.AbstractFeed;
 import org.apache.brooklyn.core.location.internal.LocationInternal;
 import org.apache.brooklyn.core.mgmt.persist.BrooklynPersistenceUtils;
 import org.apache.brooklyn.core.mgmt.rebind.AbstractBrooklynObjectRebindSupport;
@@ -58,7 +59,6 @@ import org.apache.brooklyn.core.mgmt.rebind.TreeUtils;
 import org.apache.brooklyn.core.objs.BrooklynTypes;
 import org.apache.brooklyn.core.policy.AbstractPolicy;
 import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
-import org.apache.brooklyn.sensor.feed.AbstractFeed;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.flags.FlagUtils;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/core/sensor/AttributeSensorAndConfigKey.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/AttributeSensorAndConfigKey.java b/core/src/main/java/org/apache/brooklyn/core/sensor/AttributeSensorAndConfigKey.java
index 940d949..f76baaa 100644
--- a/core/src/main/java/org/apache/brooklyn/core/sensor/AttributeSensorAndConfigKey.java
+++ b/core/src/main/java/org/apache/brooklyn/core/sensor/AttributeSensorAndConfigKey.java
@@ -27,7 +27,7 @@ import org.apache.brooklyn.core.config.BasicConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
-import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
+import org.apache.brooklyn.core.feed.ConfigToAttributes;
 import org.apache.brooklyn.util.core.flags.TypeCoercions;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/core/sensor/HttpRequestSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/HttpRequestSensor.java b/core/src/main/java/org/apache/brooklyn/core/sensor/HttpRequestSensor.java
index 79660ce..542fc01 100644
--- a/core/src/main/java/org/apache/brooklyn/core/sensor/HttpRequestSensor.java
+++ b/core/src/main/java/org/apache/brooklyn/core/sensor/HttpRequestSensor.java
@@ -26,9 +26,9 @@ import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.effector.AddSensor;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/entity/group/DynamicMultiGroupImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicMultiGroupImpl.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicMultiGroupImpl.java
index a6880b7..e914bd2 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicMultiGroupImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicMultiGroupImpl.java
@@ -30,8 +30,8 @@ import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.entity.Group;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.sensor.feed.function.FunctionFeed;
-import org.apache.brooklyn.sensor.feed.function.FunctionPollConfig;
+import org.apache.brooklyn.feed.function.FunctionFeed;
+import org.apache.brooklyn.feed.function.FunctionPollConfig;
 import org.apache.brooklyn.util.collections.MutableMap;
 
 import com.google.common.base.Function;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/entity/stock/DataEntityImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/stock/DataEntityImpl.java b/core/src/main/java/org/apache/brooklyn/entity/stock/DataEntityImpl.java
index af34e0d..7f10d5b 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/stock/DataEntityImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/stock/DataEntityImpl.java
@@ -24,8 +24,8 @@ import java.util.Map;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.entity.AbstractEntity;
-import org.apache.brooklyn.sensor.feed.function.FunctionFeed;
-import org.apache.brooklyn.sensor.feed.function.FunctionPollConfig;
+import org.apache.brooklyn.feed.function.FunctionFeed;
+import org.apache.brooklyn.feed.function.FunctionPollConfig;
 
 import com.google.common.base.Functions;
 import com.google.common.base.Supplier;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/feed/function/FunctionFeed.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/feed/function/FunctionFeed.java b/core/src/main/java/org/apache/brooklyn/feed/function/FunctionFeed.java
new file mode 100644
index 0000000..55db890
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/feed/function/FunctionFeed.java
@@ -0,0 +1,208 @@
+/*
+ * 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.feed.function;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.feed.AbstractFeed;
+import org.apache.brooklyn.core.feed.AttributePollHandler;
+import org.apache.brooklyn.core.feed.DelegatingPollHandler;
+import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
+import com.google.common.reflect.TypeToken;
+
+/**
+ * Provides a feed of attribute values, by periodically invoking functions.
+ * 
+ * Example usage (e.g. in an entity that extends SoftwareProcessImpl):
+ * <pre>
+ * {@code
+ * private FunctionFeed feed;
+ * 
+ * //@Override
+ * protected void connectSensors() {
+ *   super.connectSensors();
+ *   
+ *   feed = FunctionFeed.builder()
+ *     .entity(this)
+ *     .poll(new FunctionPollConfig<Object, Boolean>(SERVICE_UP)
+ *         .period(500, TimeUnit.MILLISECONDS)
+ *         .callable(new Callable<Boolean>() {
+ *             public Boolean call() throws Exception {
+ *               return getDriver().isRunning();
+ *             }
+ *         })
+ *         .onExceptionOrFailure(Functions.constant(Boolan.FALSE))
+ *     .build();
+ * }
+ * 
+ * {@literal @}Override
+ * protected void disconnectSensors() {
+ *   super.disconnectSensors();
+ *   if (feed != null) feed.stop();
+ * }
+ * }
+ * </pre>
+ * 
+ * @author aled
+ */
+public class FunctionFeed extends AbstractFeed {
+
+    private static final Logger log = LoggerFactory.getLogger(FunctionFeed.class);
+
+    // Treat as immutable once built
+    @SuppressWarnings("serial")
+    public static final ConfigKey<SetMultimap<FunctionPollIdentifier, FunctionPollConfig<?,?>>> POLLS = ConfigKeys.newConfigKey(
+            new TypeToken<SetMultimap<FunctionPollIdentifier, FunctionPollConfig<?,?>>>() {},
+            "polls");
+
+    public static Builder builder() {
+        return new Builder();
+    }
+    
+    public static Builder builder(String uniqueTag) {
+        return new Builder().uniqueTag(uniqueTag);
+    }
+    
+    public static class Builder {
+        private EntityLocal entity;
+        private boolean onlyIfServiceUp = false;
+        private long period = 500;
+        private TimeUnit periodUnits = TimeUnit.MILLISECONDS;
+        private List<FunctionPollConfig<?,?>> polls = Lists.newArrayList();
+        private String uniqueTag;
+        private volatile boolean built;
+
+        public Builder entity(EntityLocal val) {
+            this.entity = val;
+            return this;
+        }
+        public Builder onlyIfServiceUp() { return onlyIfServiceUp(true); }
+        public Builder onlyIfServiceUp(boolean onlyIfServiceUp) { 
+            this.onlyIfServiceUp = onlyIfServiceUp; 
+            return this; 
+        }
+        public Builder period(Duration d) {
+            return period(d.toMilliseconds(), TimeUnit.MILLISECONDS);
+        }
+        public Builder period(long millis) {
+            return period(millis, TimeUnit.MILLISECONDS);
+        }
+        public Builder period(long val, TimeUnit units) {
+            this.period = val;
+            this.periodUnits = units;
+            return this;
+        }
+        public Builder poll(FunctionPollConfig<?,?> config) {
+            polls.add(config);
+            return this;
+        }
+        public Builder uniqueTag(String uniqueTag) {
+            this.uniqueTag = uniqueTag;
+            return this;
+        }
+        public FunctionFeed build() {
+            built = true;
+            FunctionFeed result = new FunctionFeed(this);
+            result.setEntity(checkNotNull(entity, "entity"));
+            result.start();
+            return result;
+        }
+        @Override
+        protected void finalize() {
+            if (!built) log.warn("FunctionFeed.Builder created, but build() never called");
+        }
+    }
+    
+    private static class FunctionPollIdentifier {
+        final Callable<?> job;
+
+        private FunctionPollIdentifier(Callable<?> job) {
+            this.job = checkNotNull(job, "job");
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(job);
+        }
+        
+        @Override
+        public boolean equals(Object other) {
+            return (other instanceof FunctionPollIdentifier) && Objects.equal(job, ((FunctionPollIdentifier)other).job);
+        }
+    }
+
+    /**
+     * For rebind; do not call directly; use builder
+     */
+    public FunctionFeed() {
+    }
+    
+    protected FunctionFeed(Builder builder) {
+        setConfig(ONLY_IF_SERVICE_UP, builder.onlyIfServiceUp);
+        
+        SetMultimap<FunctionPollIdentifier, FunctionPollConfig<?,?>> polls = HashMultimap.<FunctionPollIdentifier,FunctionPollConfig<?,?>>create();
+        for (FunctionPollConfig<?,?> config : builder.polls) {
+            if (!config.isEnabled()) continue;
+            @SuppressWarnings({ "rawtypes", "unchecked" })
+            FunctionPollConfig<?,?> configCopy = new FunctionPollConfig(config);
+            if (configCopy.getPeriod() < 0) configCopy.period(builder.period, builder.periodUnits);
+            Callable<?> job = config.getCallable();
+            polls.put(new FunctionPollIdentifier(job), configCopy);
+        }
+        setConfig(POLLS, polls);
+        initUniqueTag(builder.uniqueTag, polls.values());
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Override
+    protected void preStart() {
+        SetMultimap<FunctionPollIdentifier, FunctionPollConfig<?, ?>> polls = getConfig(POLLS);
+        for (final FunctionPollIdentifier pollInfo : polls.keySet()) {
+            Set<FunctionPollConfig<?,?>> configs = polls.get(pollInfo);
+            long minPeriod = Integer.MAX_VALUE;
+            Set<AttributePollHandler<?>> handlers = Sets.newLinkedHashSet();
+
+            for (FunctionPollConfig<?,?> config : configs) {
+                handlers.add(new AttributePollHandler(config, entity, this));
+                if (config.getPeriod() > 0) minPeriod = Math.min(minPeriod, config.getPeriod());
+            }
+            
+            getPoller().scheduleAtFixedRate(
+                    (Callable)pollInfo.job,
+                    new DelegatingPollHandler(handlers), 
+                    minPeriod);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/feed/function/FunctionPollConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/feed/function/FunctionPollConfig.java b/core/src/main/java/org/apache/brooklyn/feed/function/FunctionPollConfig.java
new file mode 100644
index 0000000..4951868
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/feed/function/FunctionPollConfig.java
@@ -0,0 +1,111 @@
+/*
+ * 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.feed.function;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import groovy.lang.Closure;
+
+import java.util.concurrent.Callable;
+
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.feed.FeedConfig;
+import org.apache.brooklyn.core.feed.PollConfig;
+import org.apache.brooklyn.util.groovy.GroovyJavaMethods;
+import org.apache.brooklyn.util.guava.Functionals;
+import org.apache.brooklyn.util.javalang.JavaClassNames;
+
+import com.google.common.base.Supplier;
+
+public class FunctionPollConfig<S, T> extends PollConfig<S, T, FunctionPollConfig<S, T>> {
+
+    private Callable<?> callable;
+    
+    public static <T> FunctionPollConfig<?, T> forSensor(AttributeSensor<T> sensor) {
+        return new FunctionPollConfig<Object, T>(sensor);
+    }
+    
+    public FunctionPollConfig(AttributeSensor<T> sensor) {
+        super(sensor);
+    }
+
+    public FunctionPollConfig(FunctionPollConfig<S, T> other) {
+        super(other);
+        callable = other.callable;
+    }
+    
+    public Callable<? extends Object> getCallable() {
+        return callable;
+    }
+    
+    /**
+     * The {@link Callable} to be invoked on each poll.
+     * <p>
+     * Note this <em>must</em> use generics, otherwise the return type of subsequent chained
+     * calls will (e.g. to {@link FeedConfig#onException(com.google.common.base.Function)} will
+     * return the wrong type.
+     */
+    @SuppressWarnings("unchecked")
+    public <newS> FunctionPollConfig<newS, T> callable(Callable<? extends newS> val) {
+        this.callable = checkNotNull(val, "callable");
+        return (FunctionPollConfig<newS, T>) this;
+    }
+    
+    /**
+     * Supplies the value to be returned by each poll.
+     * <p>
+     * Note this <em>must</em> use generics, otherwise the return type of subsequent chained
+     * calls will (e.g. to {@link FeedConfig#onException(com.google.common.base.Function)} will
+     * return the wrong type.
+     */
+    @SuppressWarnings("unchecked")
+    public <newS> FunctionPollConfig<newS, T> supplier(final Supplier<? extends newS> val) {
+        this.callable = Functionals.callable( checkNotNull(val, "supplier") );
+        return (FunctionPollConfig<newS, T>) this;
+    }
+    
+    /** @deprecated since 0.7.0, kept for legacy compatibility when deserializing */
+    @SuppressWarnings({ "unchecked", "unused" })
+    private <newS> FunctionPollConfig<newS, T> supplierLegacy(final Supplier<? extends newS> val) {
+        checkNotNull(val, "supplier");
+        this.callable = new Callable<newS>() {
+            @Override
+            public newS call() throws Exception {
+                return val.get();
+            }
+        };
+        return (FunctionPollConfig<newS, T>) this;
+    }
+
+    public FunctionPollConfig<S, T> closure(Closure<?> val) {
+        this.callable = GroovyJavaMethods.callableFromClosure(checkNotNull(val, "closure"));
+        return this;
+    }
+
+    @Override protected String toStringBaseName() { return "fn"; }
+    @Override protected String toStringPollSource() {
+        if (callable==null) return null;
+        String cs = callable.toString();
+        if (!cs.contains( ""+Integer.toHexString(callable.hashCode()) )) {
+            return cs;
+        }
+        // if hashcode is in callable it's probably a custom internal; return class name
+        return JavaClassNames.simpleClassName(callable);
+    }
+
+}



[24/36] incubator-brooklyn git commit: Rename o.a.b.sensor.feed to o.a.b.feed and o.a.b.core.feed

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/http/HttpFeed.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/http/HttpFeed.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/http/HttpFeed.java
deleted file mode 100644
index 9ae5431..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/http/HttpFeed.java
+++ /dev/null
@@ -1,382 +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.feed.http;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.net.URI;
-import java.net.URL;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.sensor.feed.AbstractFeed;
-import org.apache.brooklyn.sensor.feed.AttributePollHandler;
-import org.apache.brooklyn.sensor.feed.DelegatingPollHandler;
-import org.apache.brooklyn.sensor.feed.Poller;
-import org.apache.brooklyn.util.core.http.HttpTool;
-import org.apache.brooklyn.util.core.http.HttpToolResponse;
-import org.apache.brooklyn.util.core.http.HttpTool.HttpClientBuilder;
-import org.apache.brooklyn.util.time.Duration;
-import org.apache.http.auth.Credentials;
-import org.apache.http.auth.UsernamePasswordCredentials;
-import org.apache.http.client.HttpClient;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Objects;
-import com.google.common.base.Optional;
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.SetMultimap;
-import com.google.common.collect.Sets;
-import com.google.common.reflect.TypeToken;
-
-/**
- * Provides a feed of attribute values, by polling over http.
- * 
- * Example usage (e.g. in an entity that extends SoftwareProcessImpl):
- * <pre>
- * {@code
- * private HttpFeed feed;
- * 
- * //@Override
- * protected void connectSensors() {
- *   super.connectSensors();
- *   
- *   feed = HttpFeed.builder()
- *       .entity(this)
- *       .period(200)
- *       .baseUri(String.format("http://%s:%s/management/subsystem/web/connector/http/read-resource", host, port))
- *       .baseUriVars(ImmutableMap.of("include-runtime","true"))
- *       .poll(new HttpPollConfig<Boolean>(SERVICE_UP)
- *           .onSuccess(HttpValueFunctions.responseCodeEquals(200))
- *           .onError(Functions.constant(false)))
- *       .poll(new HttpPollConfig<Integer>(REQUEST_COUNT)
- *           .onSuccess(HttpValueFunctions.jsonContents("requestCount", Integer.class)))
- *       .build();
- * }
- * 
- * {@literal @}Override
- * protected void disconnectSensors() {
- *   super.disconnectSensors();
- *   if (feed != null) feed.stop();
- * }
- * }
- * </pre>
- * <p>
- *  
- * This also supports giving a Supplier for the URL 
- * (e.g. {@link Entities#attributeSupplier(org.apache.brooklyn.api.entity.Entity, org.apache.brooklyn.api.event.AttributeSensor)})
- * from a sensor.  Note however that if a Supplier-based sensor is *https*,
- * https-specific initialization may not occur if the URL is not available at start time,
- * and it may report errors if that sensor is not available.
- * Some guidance for controlling enablement of a feed based on availability of a sensor
- * can be seen in HttpLatencyDetector (in brooklyn-policy). 
- * 
- * @author aled
- */
-public class HttpFeed extends AbstractFeed {
-
-    public static final Logger log = LoggerFactory.getLogger(HttpFeed.class);
-
-    @SuppressWarnings("serial")
-    public static final ConfigKey<SetMultimap<HttpPollIdentifier, HttpPollConfig<?>>> POLLS = ConfigKeys.newConfigKey(
-            new TypeToken<SetMultimap<HttpPollIdentifier, HttpPollConfig<?>>>() {},
-            "polls");
-
-    public static Builder builder() {
-        return new Builder();
-    }
-    
-    public static class Builder {
-        private EntityLocal entity;
-        private boolean onlyIfServiceUp = false;
-        private Supplier<URI> baseUriProvider;
-        private Duration period = Duration.millis(500);
-        private List<HttpPollConfig<?>> polls = Lists.newArrayList();
-        private URI baseUri;
-        private Map<String, String> baseUriVars = Maps.newLinkedHashMap();
-        private Map<String, String> headers = Maps.newLinkedHashMap();
-        private boolean suspended = false;
-        private Credentials credentials;
-        private String uniqueTag;
-        private volatile boolean built;
-
-        public Builder entity(EntityLocal val) {
-            this.entity = val;
-            return this;
-        }
-        public Builder onlyIfServiceUp() { return onlyIfServiceUp(true); }
-        public Builder onlyIfServiceUp(boolean onlyIfServiceUp) { 
-            this.onlyIfServiceUp = onlyIfServiceUp; 
-            return this; 
-        }
-        public Builder baseUri(Supplier<URI> val) {
-            if (baseUri!=null && val!=null)
-                throw new IllegalStateException("Builder cannot take both a URI and a URI Provider");
-            this.baseUriProvider = val;
-            return this;
-        }
-        public Builder baseUri(URI val) {
-            if (baseUriProvider!=null && val!=null)
-                throw new IllegalStateException("Builder cannot take both a URI and a URI Provider");
-            this.baseUri = val;
-            return this;
-        }
-        public Builder baseUrl(URL val) {
-            return baseUri(URI.create(val.toString()));
-        }
-        public Builder baseUri(String val) {
-            return baseUri(URI.create(val));
-        }
-        public Builder baseUriVars(Map<String,String> vals) {
-            baseUriVars.putAll(vals);
-            return this;
-        }
-        public Builder baseUriVar(String key, String val) {
-            baseUriVars.put(key, val);
-            return this;
-        }
-        public Builder headers(Map<String,String> vals) {
-            headers.putAll(vals);
-            return this;
-        }
-        public Builder header(String key, String val) {
-            headers.put(key, val);
-            return this;
-        }
-        public Builder period(Duration duration) {
-            this.period = duration;
-            return this;
-        }
-        public Builder period(long millis) {
-            return period(millis, TimeUnit.MILLISECONDS);
-        }
-        public Builder period(long val, TimeUnit units) {
-            return period(Duration.of(val, units));
-        }
-        public Builder poll(HttpPollConfig<?> config) {
-            polls.add(config);
-            return this;
-        }
-        public Builder suspended() {
-            return suspended(true);
-        }
-        public Builder suspended(boolean startsSuspended) {
-            this.suspended = startsSuspended;
-            return this;
-        }
-        public Builder credentials(String username, String password) {
-            this.credentials = new UsernamePasswordCredentials(username, password);
-            return this;
-        }
-        public Builder credentialsIfNotNull(String username, String password) {
-            if (username != null && password != null) {
-                this.credentials = new UsernamePasswordCredentials(username, password);
-            }
-            return this;
-        }
-        public Builder uniqueTag(String uniqueTag) {
-            this.uniqueTag = uniqueTag;
-            return this;
-        }
-        public HttpFeed build() {
-            built = true;
-            HttpFeed result = new HttpFeed(this);
-            result.setEntity(checkNotNull(entity, "entity"));
-            if (suspended) result.suspend();
-            result.start();
-            return result;
-        }
-        @Override
-        protected void finalize() {
-            if (!built) log.warn("HttpFeed.Builder created, but build() never called");
-        }
-    }
-    
-    private static class HttpPollIdentifier {
-        final String method;
-        final Supplier<URI> uriProvider;
-        final Map<String,String> headers;
-        final byte[] body;
-        final Optional<Credentials> credentials;
-        final Duration connectionTimeout;
-        final Duration socketTimeout;
-        private HttpPollIdentifier(String method, Supplier<URI> uriProvider, Map<String, String> headers, byte[] body,
-                                   Optional<Credentials> credentials, Duration connectionTimeout, Duration socketTimeout) {
-            this.method = checkNotNull(method, "method").toLowerCase();
-            this.uriProvider = checkNotNull(uriProvider, "uriProvider");
-            this.headers = checkNotNull(headers, "headers");
-            this.body = body;
-            this.credentials = checkNotNull(credentials, "credentials");
-            this.connectionTimeout = connectionTimeout;
-            this.socketTimeout = socketTimeout;
-            
-            if (!(this.method.equals("get") || this.method.equals("post"))) {
-                throw new IllegalArgumentException("Unsupported HTTP method (only supports GET and POST): "+method);
-            }
-            if (body != null && method.equalsIgnoreCase("get")) {
-                throw new IllegalArgumentException("Must not set body for http GET method");
-            }
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hashCode(method, uriProvider, headers, body, credentials);
-        }
-        
-        @Override
-        public boolean equals(Object other) {
-            if (!(other instanceof HttpPollIdentifier)) {
-                return false;
-            }
-            HttpPollIdentifier o = (HttpPollIdentifier) other;
-            return Objects.equal(method, o.method) &&
-                    Objects.equal(uriProvider, o.uriProvider) &&
-                    Objects.equal(headers, o.headers) &&
-                    Objects.equal(body, o.body) &&
-                    Objects.equal(credentials, o.credentials);
-        }
-    }
-    
-    /**
-     * For rebind; do not call directly; use builder
-     */
-    public HttpFeed() {
-    }
-    
-    protected HttpFeed(Builder builder) {
-        setConfig(ONLY_IF_SERVICE_UP, builder.onlyIfServiceUp);
-        Map<String,String> baseHeaders = ImmutableMap.copyOf(checkNotNull(builder.headers, "headers"));
-        
-        SetMultimap<HttpPollIdentifier, HttpPollConfig<?>> polls = HashMultimap.<HttpPollIdentifier,HttpPollConfig<?>>create();
-        for (HttpPollConfig<?> config : builder.polls) {
-            if (!config.isEnabled()) continue;
-            @SuppressWarnings({ "unchecked", "rawtypes" })
-            HttpPollConfig<?> configCopy = new HttpPollConfig(config);
-            if (configCopy.getPeriod() < 0) configCopy.period(builder.period);
-            String method = config.getMethod();
-            Map<String,String> headers = config.buildHeaders(baseHeaders);
-            byte[] body = config.getBody();
-            Duration connectionTimeout = config.getConnectionTimeout();
-            Duration socketTimeout = config.getSocketTimeout();
-            
-            Optional<Credentials> credentials = Optional.fromNullable(builder.credentials);
-            
-            Supplier<URI> baseUriProvider = builder.baseUriProvider;
-            if (builder.baseUri!=null) {
-                if (baseUriProvider!=null)
-                    throw new IllegalStateException("Not permitted to supply baseUri and baseUriProvider");
-                Map<String,String> baseUriVars = ImmutableMap.copyOf(checkNotNull(builder.baseUriVars, "baseUriVars"));
-                URI uri = config.buildUri(builder.baseUri, baseUriVars);
-                baseUriProvider = Suppliers.ofInstance(uri);
-            } else if (!builder.baseUriVars.isEmpty()) {
-                throw new IllegalStateException("Not permitted to supply URI vars when using a URI provider; pass the vars to the provider instead");
-            }
-            checkNotNull(baseUriProvider);
-
-            polls.put(new HttpPollIdentifier(method, baseUriProvider, headers, body, credentials, connectionTimeout, socketTimeout), configCopy);
-        }
-        setConfig(POLLS, polls);
-        initUniqueTag(builder.uniqueTag, polls.values());
-    }
-
-    @Override
-    protected void preStart() {
-        SetMultimap<HttpPollIdentifier, HttpPollConfig<?>> polls = getConfig(POLLS);
-        
-        for (final HttpPollIdentifier pollInfo : polls.keySet()) {
-            // Though HttpClients are thread safe and can take advantage of connection pooling
-            // and authentication caching, the httpcomponents documentation says:
-            //    "While HttpClient instances are thread safe and can be shared between multiple
-            //     threads of execution, it is highly recommended that each thread maintains its
-            //     own dedicated instance of HttpContext.
-            //  http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html
-            final HttpClient httpClient = createHttpClient(pollInfo);
-
-            Set<HttpPollConfig<?>> configs = polls.get(pollInfo);
-            long minPeriod = Integer.MAX_VALUE;
-            Set<AttributePollHandler<? super HttpToolResponse>> handlers = Sets.newLinkedHashSet();
-
-            for (HttpPollConfig<?> config : configs) {
-                handlers.add(new AttributePollHandler<HttpToolResponse>(config, entity, this));
-                if (config.getPeriod() > 0) minPeriod = Math.min(minPeriod, config.getPeriod());
-            }
-
-            Callable<HttpToolResponse> pollJob;
-            
-            if (pollInfo.method.equals("get")) {
-                pollJob = new Callable<HttpToolResponse>() {
-                    public HttpToolResponse call() throws Exception {
-                        if (log.isTraceEnabled()) log.trace("http polling for {} sensors at {}", entity, pollInfo);
-                        return HttpTool.httpGet(httpClient, pollInfo.uriProvider.get(), pollInfo.headers);
-                    }};
-            } else if (pollInfo.method.equals("post")) {
-                pollJob = new Callable<HttpToolResponse>() {
-                    public HttpToolResponse call() throws Exception {
-                        if (log.isTraceEnabled()) log.trace("http polling for {} sensors at {}", entity, pollInfo);
-                        return HttpTool.httpPost(httpClient, pollInfo.uriProvider.get(), pollInfo.headers, pollInfo.body);
-                    }};
-            } else if (pollInfo.method.equals("head")) {
-                pollJob = new Callable<HttpToolResponse>() {
-                    public HttpToolResponse call() throws Exception {
-                        if (log.isTraceEnabled()) log.trace("http polling for {} sensors at {}", entity, pollInfo);
-                        return HttpTool.httpHead(httpClient, pollInfo.uriProvider.get(), pollInfo.headers);
-                    }};
-            } else {
-                throw new IllegalStateException("Unexpected http method: "+pollInfo.method);
-            }
-            
-            getPoller().scheduleAtFixedRate(pollJob, new DelegatingPollHandler<HttpToolResponse>(handlers), minPeriod);
-        }
-    }
-
-    // TODO Should we really trustAll for https? Make configurable?
-    private HttpClient createHttpClient(HttpPollIdentifier pollIdentifier) {
-        URI uri = pollIdentifier.uriProvider.get();
-        HttpClientBuilder builder = HttpTool.httpClientBuilder()
-                .trustAll()
-                .laxRedirect(true);
-        if (uri != null) builder.uri(uri);
-        if (uri != null) builder.credential(pollIdentifier.credentials);
-        if (pollIdentifier.connectionTimeout != null) {
-            builder.connectionTimeout(pollIdentifier.connectionTimeout);
-        }
-        if (pollIdentifier.socketTimeout != null) {
-            builder.socketTimeout(pollIdentifier.socketTimeout);
-        }
-        return builder.build();
-    }
-
-    @SuppressWarnings("unchecked")
-    protected Poller<HttpToolResponse> getPoller() {
-        return (Poller<HttpToolResponse>) super.getPoller();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/http/HttpPollConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/http/HttpPollConfig.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/http/HttpPollConfig.java
deleted file mode 100644
index eead23f..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/http/HttpPollConfig.java
+++ /dev/null
@@ -1,160 +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.feed.http;
-
-import java.net.URI;
-import java.util.Map;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.sensor.feed.PollConfig;
-import org.apache.brooklyn.util.collections.MutableList;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.http.HttpTool;
-import org.apache.brooklyn.util.core.http.HttpToolResponse;
-import org.apache.brooklyn.util.time.Duration;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableMap;
-
-public class HttpPollConfig<T> extends PollConfig<HttpToolResponse, T, HttpPollConfig<T>> {
-
-    private String method = "GET";
-    private String suburl = "";
-    private Map<String, String> vars = ImmutableMap.<String,String>of();
-    private Map<String, String> headers = ImmutableMap.<String,String>of();
-    private byte[] body;
-    private Duration connectionTimeout;
-    private Duration socketTimeout;
-    
-    public static final Predicate<HttpToolResponse> DEFAULT_SUCCESS = new Predicate<HttpToolResponse>() {
-        @Override
-        public boolean apply(@Nullable HttpToolResponse input) {
-            return input != null && input.getResponseCode() >= 200 && input.getResponseCode() <= 399;
-        }};
-    
-    public static <T> HttpPollConfig<T> forSensor(AttributeSensor<T> sensor) {
-        return new HttpPollConfig<T>(sensor);
-    }
-    
-    public static HttpPollConfig<Void> forMultiple() {
-        return new HttpPollConfig<Void>(PollConfig.NO_SENSOR);
-    }
-    
-    public HttpPollConfig(AttributeSensor<T> sensor) {
-        super(sensor);
-        super.checkSuccess(DEFAULT_SUCCESS);
-    }
-
-    public HttpPollConfig(HttpPollConfig<T> other) {
-        super(other);
-        suburl = other.suburl;
-        vars = other.vars;
-        method = other.method;
-        headers = other.headers;
-    }
-    
-    public String getSuburl() {
-        return suburl;
-    }
-    
-    public Map<String, String> getVars() {
-        return vars;
-    }
-    
-    public Duration getConnectionTimeout() {
-        return connectionTimeout;
-    }
-    
-    public Duration getSocketTimeout() {
-        return socketTimeout;
-    }
-    
-    public String getMethod() {
-        return method;
-    }
-    
-    public byte[] getBody() {
-        return body;
-    }
-    
-    public HttpPollConfig<T> method(String val) {
-        this.method = val; return this;
-    }
-    
-    public HttpPollConfig<T> suburl(String val) {
-        this.suburl = val; return this;
-    }
-    
-    public HttpPollConfig<T> vars(Map<String,String> val) {
-        this.vars = val; return this;
-    }
-    
-    public HttpPollConfig<T> headers(Map<String,String> val) {
-        this.headers = val; return this;
-    }
-    
-    public HttpPollConfig<T> body(byte[] val) {
-        this.body = val; return this;
-    }
-    public HttpPollConfig<T> connectionTimeout(Duration val) {
-        this.connectionTimeout = val;
-        return this;
-    }
-    public HttpPollConfig<T> socketTimeout(Duration val) {
-        this.socketTimeout = val;
-        return this;
-    }
-    public URI buildUri(URI baseUri, Map<String,String> baseUriVars) {
-        String uri = (baseUri != null ? baseUri.toString() : "") + (suburl != null ? suburl : "");
-        Map<String,String> allvars = concat(baseUriVars, vars);
-        
-        if (allvars != null && allvars.size() > 0) {
-            uri += "?" + HttpTool.encodeUrlParams(allvars);
-        }
-        
-        return URI.create(uri);
-    }
-
-    public Map<String, String> buildHeaders(Map<String, String> baseHeaders) {
-        return MutableMap.<String,String>builder()
-                .putAll(baseHeaders)
-                .putAll(headers)
-                .build();
-    }
-    
-    @SuppressWarnings("unchecked")
-    private <K,V> Map<K,V> concat(Map<? extends K,? extends V> map1, Map<? extends K,? extends V> map2) {
-        if (map1 == null || map1.isEmpty()) return (Map<K,V>) map2;
-        if (map2 == null || map2.isEmpty()) return (Map<K,V>) map1;
-        
-        // TODO Not using Immutable builder, because that fails if duplicates in map1 and map2
-        return MutableMap.<K,V>builder().putAll(map1).putAll(map2).build();
-    }
-
-    @Override protected String toStringBaseName() { return "http"; }
-    @Override protected String toStringPollSource() { return suburl; }
-    @Override
-    protected MutableList<Object> equalsFields() {
-        return super.equalsFields().appendIfNotNull(method).appendIfNotNull(vars).appendIfNotNull(headers)
-            .appendIfNotNull(body).appendIfNotNull(connectionTimeout).appendIfNotNull(socketTimeout);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/http/HttpPollValue.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/http/HttpPollValue.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/http/HttpPollValue.java
deleted file mode 100644
index 04432bd..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/http/HttpPollValue.java
+++ /dev/null
@@ -1,40 +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.feed.http;
-
-import java.util.List;
-import java.util.Map;
-
-import org.apache.brooklyn.util.core.http.HttpToolResponse;
-
-/** @deprecated since 0.7.0, use {@link HttpToolResponse}.
- * the old {@link HttpPollValue} concrete class has been renamed {@link HttpToolResponse}
- * because it has nothing specific to polls. this is now just a transitional interface. */
-@Deprecated
-public interface HttpPollValue {
-
-    public int getResponseCode();
-    public String getReasonPhrase();
-    public long getStartTime();
-    public long getLatencyFullContent();
-    public long getLatencyFirstResponse();
-    public Map<String, List<String>> getHeaderLists();
-    public byte[] getContent();
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/http/HttpPolls.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/http/HttpPolls.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/http/HttpPolls.java
deleted file mode 100644
index aacd186..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/http/HttpPolls.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.feed.http;
-
-import java.net.URI;
-
-import org.apache.brooklyn.util.core.http.HttpTool;
-import org.apache.brooklyn.util.core.http.HttpToolResponse;
-import org.apache.http.impl.client.DefaultHttpClient;
-
-import com.google.common.collect.ImmutableMap;
-
-/**
- * @deprecated since 0.7; use {@link HttpTool}
- */
-@Deprecated
-public class HttpPolls {
-
-    public static HttpToolResponse executeSimpleGet(URI uri) {
-        return HttpTool.httpGet(new DefaultHttpClient(), uri, ImmutableMap.<String,String>of());
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/http/HttpValueFunctions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/http/HttpValueFunctions.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/http/HttpValueFunctions.java
deleted file mode 100644
index 3fcbe07..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/http/HttpValueFunctions.java
+++ /dev/null
@@ -1,154 +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.feed.http;
-
-import java.util.List;
-
-import org.apache.brooklyn.util.core.http.HttpToolResponse;
-import org.apache.brooklyn.util.guava.Functionals;
-
-import com.google.common.base.Function;
-import com.google.common.base.Functions;
-import com.google.common.base.Predicates;
-import com.google.common.collect.Lists;
-import com.google.gson.JsonElement;
-
-public class HttpValueFunctions {
-
-    private HttpValueFunctions() {} // instead use static utility methods
-    
-    public static Function<HttpToolResponse, Integer> responseCode() {
-        return new ResponseCode();
-    }
-    
-    /** @deprecated since 0.7.0; only here for deserialization of persisted state */
-    private static Function<HttpToolResponse, Integer> responseCodeLegacy() {
-        return new Function<HttpToolResponse, Integer>() {
-            @Override public Integer apply(HttpToolResponse input) {
-                return input.getResponseCode();
-            }
-        };
-    }
-
-    private static class ResponseCode implements Function<HttpToolResponse, Integer> {
-        @Override public Integer apply(HttpToolResponse input) {
-            return input.getResponseCode();
-        }
-    }
-
-    public static Function<HttpToolResponse, Boolean> responseCodeEquals(final int expected) {
-        return Functionals.chain(HttpValueFunctions.responseCode(), Functions.forPredicate(Predicates.equalTo(expected)));
-    }
-    
-    public static Function<HttpToolResponse, Boolean> responseCodeEquals(final int... expected) {
-        List<Integer> expectedList = Lists.newArrayList();
-        for (int e : expected) {
-            expectedList.add((Integer)e);
-        }
-        return Functionals.chain(HttpValueFunctions.responseCode(), Functions.forPredicate(Predicates.in(expectedList)));
-    }
-
-    public static Function<HttpToolResponse, String> stringContentsFunction() {
-        return new StringContents();
-    }
-    
-    /** @deprecated since 0.7.0; only here for deserialization of persisted state */
-    private static Function<HttpToolResponse, String> stringContentsFunctionLegacy() {
-        return new Function<HttpToolResponse, String>() {
-            @Override public String apply(HttpToolResponse input) {
-                return input.getContentAsString();
-            }
-        };
-    }
-
-    private static class StringContents implements Function<HttpToolResponse, String> {
-        @Override public String apply(HttpToolResponse input) {
-            return input.getContentAsString();
-        }
-    }
-
-    public static Function<HttpToolResponse, JsonElement> jsonContents() {
-        return Functionals.chain(stringContentsFunction(), JsonFunctions.asJson());
-    }
-    
-    public static <T> Function<HttpToolResponse, T> jsonContents(String element, Class<T> expected) {
-        return jsonContents(new String[] {element}, expected);
-    }
-    
-    public static <T> Function<HttpToolResponse, T> jsonContents(String[] elements, Class<T> expected) {
-        return Functionals.chain(jsonContents(), JsonFunctions.walk(elements), JsonFunctions.cast(expected));
-    }
-
-    public static <T> Function<HttpToolResponse, T> jsonContentsFromPath(String path){
-        return Functionals.chain(jsonContents(), JsonFunctions.<T>getPath(path));
-    }
-    
-    public static Function<HttpToolResponse, Long> latency() {
-        return new Latency();
-    }
-
-    /** @deprecated since 0.7.0; only here for deserialization of persisted state */
-    private static Function<HttpToolResponse, Long> latencyLegacy() {
-        return new Function<HttpToolResponse, Long>() {
-            public Long apply(HttpToolResponse input) {
-                return input.getLatencyFullContent();
-            }
-        };
-    }
-
-    private static class Latency implements Function<HttpToolResponse, Long> {
-        public Long apply(HttpToolResponse input) {
-            return input.getLatencyFullContent();
-        }
-    };
-
-    public static Function<HttpToolResponse, Boolean> containsHeader(String header) {
-        return new ContainsHeader(header);
-    }
-
-    private static class ContainsHeader implements Function<HttpToolResponse, Boolean> {
-        private final String header;
-
-        public ContainsHeader(String header) {
-            this.header = header;
-        }
-        @Override
-        public Boolean apply(HttpToolResponse input) {
-            List<String> actual = input.getHeaderLists().get(header);
-            return actual != null && actual.size() > 0;
-        }
-    }
-    
-
-    /** @deprecated since 0.7.0 use {@link Functionals#chain(Function, Function)} */ @Deprecated
-    public static <A,B,C> Function<A,C> chain(final Function<A,? extends B> f1, final Function<B,C> f2) {
-        return Functionals.chain(f1, f2);
-    }
-    
-    /** @deprecated since 0.7.0 use {@link Functionals#chain(Function, Function, Function)} */ @Deprecated
-    public static <A,B,C,D> Function<A,D> chain(final Function<A,? extends B> f1, final Function<B,? extends C> f2, final Function<C,D> f3) {
-        return Functionals.chain(f1, f2, f3);
-    }
-
-    /** @deprecated since 0.7.0 use {@link Functionals#chain(Function, Function, Function, Function)} */ @Deprecated
-    public static <A,B,C,D,E> Function<A,E> chain(final Function<A,? extends B> f1, final Function<B,? extends C> f2, final Function<C,? extends D> f3, final Function<D,E> f4) {
-        return Functionals.chain(f1, f2, f3, f4);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/http/JsonFunctions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/http/JsonFunctions.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/http/JsonFunctions.java
deleted file mode 100644
index f84109f..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/http/JsonFunctions.java
+++ /dev/null
@@ -1,235 +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.feed.http;
-
-import java.lang.reflect.Array;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.Arrays;
-import java.util.List;
-import java.util.NoSuchElementException;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.util.guava.Functionals;
-import org.apache.brooklyn.util.guava.Maybe;
-import org.apache.brooklyn.util.guava.MaybeFunctions;
-
-import com.google.common.base.Function;
-import com.google.common.base.Splitter;
-import com.google.common.collect.Lists;
-import com.google.gson.*;
-import com.jayway.jsonpath.JsonPath;
-
-public class JsonFunctions {
-
-    private JsonFunctions() {} // instead use static utility methods
-    
-    public static Function<String, JsonElement> asJson() {
-        return new Function<String, JsonElement>() {
-            @Override public JsonElement apply(String input) {
-                return new JsonParser().parse(input);
-            }
-        };
-    }
-
-    public static <T> Function<JsonElement, List<T>> forEach(final Function<JsonElement, T> func) {
-        return new Function<JsonElement, List<T>>() {
-            @Override public List<T> apply(JsonElement input) {
-                JsonArray array = (JsonArray) input;
-                List<T> result = Lists.newArrayList();
-                for (int i = 0; i < array.size(); i++) {
-                    result.add(func.apply(array.get(i)));
-                }
-                return result;
-            }
-        };
-    }
-
-    
-    /** as {@link #walkM(Iterable)} taking a single string consisting of a dot separated path */
-    public static Function<JsonElement, JsonElement> walk(String elementOrDotSeparatedElements) {
-        return walk( Splitter.on('.').split(elementOrDotSeparatedElements) );
-    }
-
-    /** as {@link #walkM(Iterable)} taking a series of strings (dot separators not respected here) */
-    public static Function<JsonElement, JsonElement> walk(final String... elements) {
-        return walk(Arrays.asList(elements));
-    }
-
-    /** returns a function which traverses the supplied path of entries in a json object (maps of maps of maps...), 
-     * @throws NoSuchElementException if any path is not present as a key in that map */
-    public static Function<JsonElement, JsonElement> walk(final Iterable<String> elements) {
-        // could do this instead, pointing at Maybe for this, and for walkN, but it's slightly less efficient
-//      return Functionals.chain(MaybeFunctions.<JsonElement>wrap(), walkM(elements), MaybeFunctions.<JsonElement>get());
-
-        return new Function<JsonElement, JsonElement>() {
-            @Override public JsonElement apply(JsonElement input) {
-                JsonElement curr = input;
-                for (String element : elements) {
-                    JsonObject jo = curr.getAsJsonObject();
-                    curr = jo.get(element);
-                    if (curr==null)
-                        throw new NoSuchElementException("No element '"+element+" in JSON, when walking "+elements);
-                }
-                return curr;
-            }
-        };
-    }
-
-    
-    /** as {@link #walk(String)} but if any element is not found it simply returns null */
-    public static Function<JsonElement, JsonElement> walkN(@Nullable String elements) {
-        return walkN( Splitter.on('.').split(elements) );
-    }
-
-    /** as {@link #walk(String...))} but if any element is not found it simply returns null */
-    public static Function<JsonElement, JsonElement> walkN(final String... elements) {
-        return walkN(Arrays.asList(elements));
-    }
-
-    /** as {@link #walk(Iterable))} but if any element is not found it simply returns null */
-    public static Function<JsonElement, JsonElement> walkN(final Iterable<String> elements) {
-        return new Function<JsonElement, JsonElement>() {
-            @Override public JsonElement apply(JsonElement input) {
-                JsonElement curr = input;
-                for (String element : elements) {
-                    if (curr==null) return null;
-                    JsonObject jo = curr.getAsJsonObject();
-                    curr = jo.get(element);
-                }
-                return curr;
-            }
-        };
-    }
-
-    /** as {@link #walk(String))} and {@link #walk(Iterable)} */
-    public static Function<Maybe<JsonElement>, Maybe<JsonElement>> walkM(@Nullable String elements) {
-        return walkM( Splitter.on('.').split(elements) );
-    }
-
-    /** as {@link #walk(String...))} and {@link #walk(Iterable)} */
-    public static Function<Maybe<JsonElement>, Maybe<JsonElement>> walkM(final String... elements) {
-        return walkM(Arrays.asList(elements));
-    }
-
-    /** as {@link #walk(Iterable))} but working with objects which {@link Maybe} contain {@link JsonElement},
-     * simply preserving a {@link Maybe#absent()} object if additional walks are requested upon it
-     * (cf jquery) */
-    public static Function<Maybe<JsonElement>, Maybe<JsonElement>> walkM(final Iterable<String> elements) {
-        return new Function<Maybe<JsonElement>, Maybe<JsonElement>>() {
-            @Override public Maybe<JsonElement> apply(Maybe<JsonElement> input) {
-                Maybe<JsonElement> curr = input;
-                for (String element : elements) {
-                    if (curr.isAbsent()) return curr;
-                    JsonObject jo = curr.get().getAsJsonObject();
-                    JsonElement currO = jo.get(element);
-                    if (currO==null) return Maybe.absent("No element '"+element+" in JSON, when walking "+elements);
-                    curr = Maybe.of(currO);
-                }
-                return curr;
-            }
-        };
-    }
-
-    /**
-     * returns an element from a single json primitive value given a full path {@link com.jayway.jsonpath.JsonPath}
-     */
-    public static <T> Function<JsonElement,T> getPath(final String path) {
-        return new Function<JsonElement, T>() {
-            @SuppressWarnings("unchecked")
-            @Override public T apply(JsonElement input) {
-                String jsonString = input.toString();
-                Object rawElement = JsonPath.read(jsonString, path);
-                return (T) rawElement;
-            }
-        };
-    }
-
-    @SuppressWarnings("unchecked")
-    public static <T> Function<JsonElement, T> cast(final Class<T> expected) {
-        return new Function<JsonElement, T>() {
-            @Override public T apply(JsonElement input) {
-                if (input == null) {
-                    return (T) null;
-                } else if (input.isJsonNull()) {
-                    return (T) null;
-                } else if (expected == boolean.class || expected == Boolean.class) {
-                    return (T) (Boolean) input.getAsBoolean();
-                } else if (expected == char.class || expected == Character.class) {
-                    return (T) (Character) input.getAsCharacter();
-                } else if (expected == byte.class || expected == Byte.class) {
-                    return (T) (Byte) input.getAsByte();
-                } else if (expected == short.class || expected == Short.class) {
-                    return (T) (Short) input.getAsShort();
-                } else if (expected == int.class || expected == Integer.class) {
-                    return (T) (Integer) input.getAsInt();
-                } else if (expected == long.class || expected == Long.class) {
-                    return (T) (Long) input.getAsLong();
-                } else if (expected == float.class || expected == Float.class) {
-                    return (T) (Float) input.getAsFloat();
-                } else if (expected == double.class || expected == Double.class) {
-                    return (T) (Double) input.getAsDouble();
-                } else if (expected == BigDecimal.class) {
-                    return (T) input.getAsBigDecimal();
-                } else if (expected == BigInteger.class) {
-                    return (T) input.getAsBigInteger();
-                } else if (Number.class.isAssignableFrom(expected)) {
-                    // TODO Will result in a class-cast if it's an unexpected sub-type of Number not handled above
-                    return (T) input.getAsNumber();
-                } else if (expected == String.class) {
-                    return (T) input.getAsString();
-                } else if (expected.isArray()) {
-                    JsonArray array = input.getAsJsonArray();
-                    Class<?> componentType = expected.getComponentType();
-                    if (JsonElement.class.isAssignableFrom(componentType)) {
-                        JsonElement[] result = new JsonElement[array.size()];
-                        for (int i = 0; i < array.size(); i++) {
-                            result[i] = array.get(i);
-                        }
-                        return (T) result;
-                    } else {
-                        Object[] result = (Object[]) Array.newInstance(componentType, array.size());
-                        for (int i = 0; i < array.size(); i++) {
-                            result[i] = cast(componentType).apply(array.get(i));
-                        }
-                        return (T) result;
-                    }
-                } else {
-                    throw new IllegalArgumentException("Cannot cast json element to type "+expected);
-                }
-            }
-        };
-    }
-    
-    public static <T> Function<Maybe<JsonElement>, T> castM(final Class<T> expected) {
-        return Functionals.chain(MaybeFunctions.<JsonElement>get(), cast(expected));
-    }
-    
-    public static <T> Function<Maybe<JsonElement>, T> castM(final Class<T> expected, final T defaultValue) {
-        return new Function<Maybe<JsonElement>, T>() {
-            @Override
-            public T apply(Maybe<JsonElement> input) {
-                if (input.isAbsent()) return defaultValue;
-                return cast(expected).apply(input.get());
-            }
-        };
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/shell/ShellFeed.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/shell/ShellFeed.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/shell/ShellFeed.java
deleted file mode 100644
index 19e5bf5..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/shell/ShellFeed.java
+++ /dev/null
@@ -1,273 +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.feed.shell;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.io.File;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.mgmt.ExecutionContext;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.sensor.feed.AbstractFeed;
-import org.apache.brooklyn.sensor.feed.AttributePollHandler;
-import org.apache.brooklyn.sensor.feed.DelegatingPollHandler;
-import org.apache.brooklyn.sensor.feed.Poller;
-import org.apache.brooklyn.sensor.feed.function.FunctionFeed;
-import org.apache.brooklyn.sensor.feed.ssh.SshFeed;
-import org.apache.brooklyn.sensor.feed.ssh.SshPollValue;
-import org.apache.brooklyn.util.core.task.system.ProcessTaskFactory;
-import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
-import org.apache.brooklyn.util.core.task.system.internal.SystemProcessTaskFactory.ConcreteSystemProcessTaskFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Objects;
-import com.google.common.base.Optional;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.SetMultimap;
-import com.google.common.collect.Sets;
-import com.google.common.reflect.TypeToken;
-
-/**
- * Provides a feed of attribute values, by executing shell commands (on the local machine where 
- * this instance of brooklyn is running). Useful e.g. for paas tools such as Cloud Foundry vmc 
- * which operate against a remote target.
- * 
- * Example usage (e.g. in an entity that extends SoftwareProcessImpl):
- * <pre>
- * {@code
- * private ShellFeed feed;
- * 
- * //@Override
- * protected void connectSensors() {
- *   super.connectSensors();
- *   
- *   feed = ShellFeed.builder()
- *       .entity(this)
- *       .machine(mySshMachineLachine)
- *       .poll(new ShellPollConfig<Long>(DISK_USAGE)
- *           .command("df -P | grep /dev")
- *           .failOnNonZeroResultCode(true)
- *           .onSuccess(new Function<SshPollValue, Long>() {
- *                public Long apply(SshPollValue input) {
- *                  String[] parts = input.getStdout().split("[ \\t]+");
- *                  return Long.parseLong(parts[2]);
- *                }}))
- *       .build();
- * }
- * 
- * {@literal @}Override
- * protected void disconnectSensors() {
- *   super.disconnectSensors();
- *   if (feed != null) feed.stop();
- * }
- * }
- * </pre>
- * 
- * @see SshFeed (to run on remote machines)
- * @see FunctionFeed (for arbitrary functions)
- * 
- * @author aled
- */
-public class ShellFeed extends AbstractFeed {
-
-    public static final Logger log = LoggerFactory.getLogger(ShellFeed.class);
-
-    @SuppressWarnings("serial")
-    private static final ConfigKey<SetMultimap<ShellPollIdentifier, ShellPollConfig<?>>> POLLS = ConfigKeys.newConfigKey(
-            new TypeToken<SetMultimap<ShellPollIdentifier, ShellPollConfig<?>>>() {},
-            "polls");
-
-    public static Builder builder() {
-        return new Builder();
-    }
-    
-    public static class Builder {
-        private EntityLocal entity;
-        private long period = 500;
-        private TimeUnit periodUnits = TimeUnit.MILLISECONDS;
-        private List<ShellPollConfig<?>> polls = Lists.newArrayList();
-        private String uniqueTag;
-        private volatile boolean built;
-        
-        public Builder entity(EntityLocal val) {
-            this.entity = val;
-            return this;
-        }
-        public Builder period(long millis) {
-            return period(millis, TimeUnit.MILLISECONDS);
-        }
-        public Builder period(long val, TimeUnit units) {
-            this.period = val;
-            this.periodUnits = units;
-            return this;
-        }
-        public Builder poll(ShellPollConfig<?> config) {
-            polls.add(config);
-            return this;
-        }
-        public Builder uniqueTag(String uniqueTag) {
-            this.uniqueTag = uniqueTag;
-            return this;
-        }
-        public ShellFeed build() {
-            built = true;
-            ShellFeed result = new ShellFeed(this);
-            result.setEntity(checkNotNull(entity, "entity"));
-            result.start();
-            return result;
-        }
-        @Override
-        protected void finalize() {
-            if (!built) log.warn("ShellFeed.Builder created, but build() never called");
-        }
-    }
-    
-    private static class ShellPollIdentifier {
-        final String command;
-        final Map<String, String> env;
-        final File dir;
-        final String input;
-        final String context;
-        final long timeout;
-
-        private ShellPollIdentifier(String command, Map<String, String> env, File dir, String input, String context, long timeout) {
-            this.command = checkNotNull(command, "command");
-            this.env = checkNotNull(env, "env");
-            this.dir = dir;
-            this.input = input;
-            this.context = checkNotNull(context, "context");
-            this.timeout = timeout;
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hashCode(command, env, dir, input, timeout);
-        }
-        
-        @Override
-        public boolean equals(Object other) {
-            if (!(other instanceof ShellPollIdentifier)) {
-                return false;
-            }
-            ShellPollIdentifier o = (ShellPollIdentifier) other;
-            return Objects.equal(command, o.command) &&
-                    Objects.equal(env, o.env) &&
-                    Objects.equal(dir, o.dir) &&
-                    Objects.equal(input, o.input) &&
-                    Objects.equal(timeout, o.timeout);
-        }
-    }
-    
-    /**
-     * For rebind; do not call directly; use builder
-     */
-    public ShellFeed() {
-    }
-
-    protected ShellFeed(Builder builder) {
-        super();
-
-        SetMultimap<ShellPollIdentifier, ShellPollConfig<?>> polls = HashMultimap.<ShellPollIdentifier,ShellPollConfig<?>>create();
-        for (ShellPollConfig<?> config : builder.polls) {
-            if (!config.isEnabled()) continue;
-            @SuppressWarnings({ "unchecked", "rawtypes" })
-            ShellPollConfig<?> configCopy = new ShellPollConfig(config);
-            if (configCopy.getPeriod() < 0) configCopy.period(builder.period, builder.periodUnits);
-            String command = config.getCommand();
-            Map<String, String> env = config.getEnv();
-            File dir = config.getDir();
-            String input = config.getInput();
-            String context = config.getSensor().getName();
-            long timeout = config.getTimeout();
-
-            polls.put(new ShellPollIdentifier(command, env, dir, input, context, timeout), configCopy);
-        }
-        setConfig(POLLS, polls);
-        initUniqueTag(builder.uniqueTag, polls.values());
-    }
-
-    @Override
-    protected void preStart() {
-        SetMultimap<ShellPollIdentifier, ShellPollConfig<?>> polls = getConfig(POLLS);
-        
-        for (final ShellPollIdentifier pollInfo : polls.keySet()) {
-            Set<ShellPollConfig<?>> configs = polls.get(pollInfo);
-            long minPeriod = Integer.MAX_VALUE;
-            Set<AttributePollHandler<? super SshPollValue>> handlers = Sets.newLinkedHashSet();
-
-            for (ShellPollConfig<?> config : configs) {
-                handlers.add(new AttributePollHandler<SshPollValue>(config, entity, this));
-                if (config.getPeriod() > 0) minPeriod = Math.min(minPeriod, config.getPeriod());
-            }
-
-            final ProcessTaskFactory<?> taskFactory = newTaskFactory(pollInfo.command, pollInfo.env, pollInfo.dir, 
-                    pollInfo.input, pollInfo.context, pollInfo.timeout);
-            final ExecutionContext executionContext = ((EntityInternal) entity).getManagementSupport().getExecutionContext();
-
-            getPoller().scheduleAtFixedRate(
-                    new Callable<SshPollValue>() {
-                        @Override public SshPollValue call() throws Exception {
-                            ProcessTaskWrapper<?> taskWrapper = taskFactory.newTask();
-                            executionContext.submit(taskWrapper);
-                            taskWrapper.block();
-                            Optional<Integer> exitCode = Optional.fromNullable(taskWrapper.getExitCode());
-                            return new SshPollValue(null, exitCode.or(-1), taskWrapper.getStdout(), taskWrapper.getStderr());
-                        }}, 
-                    new DelegatingPollHandler<SshPollValue>(handlers), 
-                    minPeriod);
-        }
-    }
-    
-    @SuppressWarnings("unchecked")
-    protected Poller<SshPollValue> getPoller() {
-        return (Poller<SshPollValue>) super.getPoller();
-    }
-    
-    /**
-     * Executes the given command (using `bash -l -c $command`, so as to have a good path set).
-     * 
-     * @param command The command to execute
-     * @param env     Environment variable settings, in format name=value
-     * @param dir     Working directory, or null to inherit from current process
-     * @param input   Input to send to the command (if not null)
-     */
-    protected ProcessTaskFactory<?> newTaskFactory(final String command, Map<String,String> env, File dir, String input, final String summary, final long timeout) {
-        // FIXME Add generic timeout() support to task ExecutionManager
-        if (timeout > 0) {
-            log.warn("Timeout ({}ms) not currently supported for ShellFeed {}", timeout, this);
-        }
-
-        return new ConcreteSystemProcessTaskFactory<Object>(command)
-                .environmentVariables(env)
-                .loginShell(true)
-                .directory(dir)
-                .runAsCommand()
-                .summary(summary);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/shell/ShellPollConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/shell/ShellPollConfig.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/shell/ShellPollConfig.java
deleted file mode 100644
index 782b094..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/shell/ShellPollConfig.java
+++ /dev/null
@@ -1,125 +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.feed.shell;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.io.File;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.sensor.feed.PollConfig;
-import org.apache.brooklyn.sensor.feed.ssh.SshPollValue;
-import org.apache.brooklyn.util.collections.MutableList;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.Maps;
-
-public class ShellPollConfig<T> extends PollConfig<SshPollValue, T, ShellPollConfig<T>> {
-
-    private String command;
-    private Map<String,String> env = Maps.newLinkedHashMap();
-    private long timeout = -1;
-    private File dir;
-    private String input;
-
-    public static final Predicate<SshPollValue> DEFAULT_SUCCESS = new Predicate<SshPollValue>() {
-        @Override
-        public boolean apply(@Nullable SshPollValue input) {
-            return input != null && input.getExitStatus() == 0;
-        }};
-
-    public ShellPollConfig(AttributeSensor<T> sensor) {
-        super(sensor);
-        super.checkSuccess(DEFAULT_SUCCESS);
-    }
-
-    public ShellPollConfig(ShellPollConfig<T> other) {
-        super(other);
-        command = other.command;
-        env = other.env;
-        timeout = other.timeout;
-        dir = other.dir;
-        input = other.input;
-    }
-    
-    public String getCommand() {
-        return command;
-    }
-    
-    public Map<String, String> getEnv() {
-        return env;
-    }
-
-    public File getDir() {
-        return dir;
-    }
-
-    public String getInput() {
-        return input;
-    }
-    
-    public long getTimeout() {
-        return timeout;
-    }
-    
-    public ShellPollConfig<T> command(String val) {
-        this.command = val;
-        return this;
-    }
-
-    public ShellPollConfig<T> env(String key, String val) {
-        env.put(checkNotNull(key, "key"), checkNotNull(val, "val"));
-        return this;
-    }
-    
-    public ShellPollConfig<T> env(Map<String,String> val) {
-        for (Map.Entry<String, String> entry : checkNotNull(val, "map").entrySet()) {
-            env(entry.getKey(), entry.getValue());
-        }
-        return this;
-    }
-    
-    public ShellPollConfig<T> dir(File val) {
-        this.dir = val;
-        return this;
-    }
-    
-    public ShellPollConfig<T> input(String val) {
-        this.input = val;
-        return this;
-    }
-    
-    public ShellPollConfig<T> timeout(long timeout) {
-        return timeout(timeout, TimeUnit.MILLISECONDS);
-    }
-    
-    public ShellPollConfig<T> timeout(long timeout, TimeUnit units) {
-        this.timeout = units.toMillis(timeout);
-        return this;
-    }
-
-    @Override protected String toStringBaseName() { return "shell"; }
-    @Override protected String toStringPollSource() { return command; }
-    @Override protected MutableList<Object> equalsFields() { return super.equalsFields().appendIfNotNull(command); }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/ssh/SshFeed.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/ssh/SshFeed.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/ssh/SshFeed.java
deleted file mode 100644
index 6e5a485..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/ssh/SshFeed.java
+++ /dev/null
@@ -1,290 +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.feed.ssh;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.location.Locations;
-import org.apache.brooklyn.core.location.Machines;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.feed.AbstractFeed;
-import org.apache.brooklyn.sensor.feed.AttributePollHandler;
-import org.apache.brooklyn.sensor.feed.DelegatingPollHandler;
-import org.apache.brooklyn.sensor.feed.Poller;
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.core.internal.ssh.SshTool;
-import org.apache.brooklyn.util.time.Duration;
-
-import com.google.common.base.Objects;
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.common.collect.SetMultimap;
-import com.google.common.collect.Sets;
-import com.google.common.reflect.TypeToken;
-
-/**
- * Provides a feed of attribute values, by polling over ssh.
- * 
- * Example usage (e.g. in an entity that extends SoftwareProcessImpl):
- * <pre>
- * {@code
- * private SshFeed feed;
- * 
- * //@Override
- * protected void connectSensors() {
- *   super.connectSensors();
- *   
- *   feed = SshFeed.builder()
- *       .entity(this)
- *       .machine(mySshMachineLachine)
- *       .poll(new SshPollConfig<Boolean>(SERVICE_UP)
- *           .command("rabbitmqctl -q status")
- *           .onSuccess(new Function<SshPollValue, Boolean>() {
- *               public Boolean apply(SshPollValue input) {
- *                 return (input.getExitStatus() == 0);
- *               }}))
- *       .build();
- * }
- * 
- * {@literal @}Override
- * protected void disconnectSensors() {
- *   super.disconnectSensors();
- *   if (feed != null) feed.stop();
- * }
- * }
- * </pre>
- * 
- * @author aled
- */
-public class SshFeed extends AbstractFeed {
-
-    public static final Logger log = LoggerFactory.getLogger(SshFeed.class);
-    
-    @SuppressWarnings("serial")
-    public static final ConfigKey<Supplier<SshMachineLocation>> MACHINE = ConfigKeys.newConfigKey(
-            new TypeToken<Supplier<SshMachineLocation>>() {},
-            "machine");
-    
-    public static final ConfigKey<Boolean> EXEC_AS_COMMAND = ConfigKeys.newBooleanConfigKey("execAsCommand");
-    
-    @SuppressWarnings("serial")
-    public static final ConfigKey<SetMultimap<SshPollIdentifier, SshPollConfig<?>>> POLLS = ConfigKeys.newConfigKey(
-            new TypeToken<SetMultimap<SshPollIdentifier, SshPollConfig<?>>>() {},
-            "polls");
-    
-    public static Builder builder() {
-        return new Builder();
-    }
-    
-    public static class Builder {
-        private EntityLocal entity;
-        private boolean onlyIfServiceUp = false;
-        private Supplier<SshMachineLocation> machine;
-        private Duration period = Duration.of(500, TimeUnit.MILLISECONDS);
-        private List<SshPollConfig<?>> polls = Lists.newArrayList();
-        private boolean execAsCommand = false;
-        private String uniqueTag;
-        private volatile boolean built;
-        
-        public Builder entity(EntityLocal val) {
-            this.entity = val;
-            return this;
-        }
-        public Builder onlyIfServiceUp() { return onlyIfServiceUp(true); }
-        public Builder onlyIfServiceUp(boolean onlyIfServiceUp) { 
-            this.onlyIfServiceUp = onlyIfServiceUp; 
-            return this; 
-        }
-        /** optional, to force a machine; otherwise it is inferred from the entity */
-        public Builder machine(SshMachineLocation val) { return machine(Suppliers.ofInstance(val)); }
-        /** optional, to force a machine; otherwise it is inferred from the entity */
-        public Builder machine(Supplier<SshMachineLocation> val) {
-            this.machine = val;
-            return this;
-        }
-        public Builder period(Duration period) {
-            this.period = period;
-            return this;
-        }
-        public Builder period(long millis) {
-            return period(Duration.of(millis, TimeUnit.MILLISECONDS));
-        }
-        public Builder period(long val, TimeUnit units) {
-            return period(Duration.of(val, units));
-        }
-        public Builder poll(SshPollConfig<?> config) {
-            polls.add(config);
-            return this;
-        }
-        public Builder execAsCommand() {
-            execAsCommand = true;
-            return this;
-        }
-        public Builder execAsScript() {
-            execAsCommand = false;
-            return this;
-        }
-        public Builder uniqueTag(String uniqueTag) {
-            this.uniqueTag = uniqueTag;
-            return this;
-        }
-        public SshFeed build() {
-            built = true;
-            SshFeed result = new SshFeed(this);
-            result.setEntity(checkNotNull(entity, "entity"));
-            result.start();
-            return result;
-        }
-        @Override
-        protected void finalize() {
-            if (!built) log.warn("SshFeed.Builder created, but build() never called");
-        }
-    }
-    
-    private static class SshPollIdentifier {
-        final Supplier<String> command;
-        final Supplier<Map<String, String>> env;
-
-        private SshPollIdentifier(Supplier<String> command, Supplier<Map<String, String>> env) {
-            this.command = checkNotNull(command, "command");
-            this.env = checkNotNull(env, "env");
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hashCode(command, env);
-        }
-        
-        @Override
-        public boolean equals(Object other) {
-            if (!(other instanceof SshPollIdentifier)) {
-                return false;
-            }
-            SshPollIdentifier o = (SshPollIdentifier) other;
-            return Objects.equal(command, o.command) &&
-                    Objects.equal(env, o.env);
-        }
-    }
-    
-    /** @deprecated since 0.7.0, use static convenience on {@link Locations} */
-    @Deprecated
-    public static SshMachineLocation getMachineOfEntity(Entity entity) {
-        return Machines.findUniqueSshMachineLocation(entity.getLocations()).orNull();
-    }
-
-    /**
-     * For rebind; do not call directly; use builder
-     */
-    public SshFeed() {
-    }
-    
-    protected SshFeed(final Builder builder) {
-        setConfig(ONLY_IF_SERVICE_UP, builder.onlyIfServiceUp);
-        setConfig(MACHINE, builder.machine != null ? builder.machine : null);
-        setConfig(EXEC_AS_COMMAND, builder.execAsCommand);
-        
-        SetMultimap<SshPollIdentifier, SshPollConfig<?>> polls = HashMultimap.<SshPollIdentifier,SshPollConfig<?>>create();
-        for (SshPollConfig<?> config : builder.polls) {
-            @SuppressWarnings({ "unchecked", "rawtypes" })
-            SshPollConfig<?> configCopy = new SshPollConfig(config);
-            if (configCopy.getPeriod() < 0) configCopy.period(builder.period);
-            polls.put(new SshPollIdentifier(config.getCommandSupplier(), config.getEnvSupplier()), configCopy);
-        }
-        setConfig(POLLS, polls);
-        initUniqueTag(builder.uniqueTag, polls.values());
-    }
-
-    protected SshMachineLocation getMachine() {
-        Supplier<SshMachineLocation> supplier = getConfig(MACHINE);
-        if (supplier != null) {
-            return supplier.get();
-        } else {
-            return Locations.findUniqueSshMachineLocation(entity.getLocations()).get();
-        }
-    }
-    
-    @Override
-    protected void preStart() {
-        SetMultimap<SshPollIdentifier, SshPollConfig<?>> polls = getConfig(POLLS);
-        
-        for (final SshPollIdentifier pollInfo : polls.keySet()) {
-            Set<SshPollConfig<?>> configs = polls.get(pollInfo);
-            long minPeriod = Integer.MAX_VALUE;
-            Set<AttributePollHandler<? super SshPollValue>> handlers = Sets.newLinkedHashSet();
-
-            for (SshPollConfig<?> config : configs) {
-                handlers.add(new AttributePollHandler<SshPollValue>(config, entity, this));
-                if (config.getPeriod() > 0) minPeriod = Math.min(minPeriod, config.getPeriod());
-            }
-            
-            getPoller().scheduleAtFixedRate(
-                    new Callable<SshPollValue>() {
-                        public SshPollValue call() throws Exception {
-                            return exec(pollInfo.command.get(), pollInfo.env.get());
-                        }}, 
-                    new DelegatingPollHandler<SshPollValue>(handlers),
-                    minPeriod);
-        }
-    }
-    
-    @SuppressWarnings("unchecked")
-    protected Poller<SshPollValue> getPoller() {
-        return (Poller<SshPollValue>) super.getPoller();
-    }
-    
-    private SshPollValue exec(String command, Map<String,String> env) throws IOException {
-        SshMachineLocation machine = getMachine();
-        Boolean execAsCommand = getConfig(EXEC_AS_COMMAND);
-        if (log.isTraceEnabled()) log.trace("Ssh polling for {}, executing {} with env {}", new Object[] {machine, command, env});
-        ByteArrayOutputStream stdout = new ByteArrayOutputStream();
-        ByteArrayOutputStream stderr = new ByteArrayOutputStream();
-
-        int exitStatus;
-        ConfigBag flags = ConfigBag.newInstance()
-            .configure(SshTool.PROP_NO_EXTRA_OUTPUT, true)
-            .configure(SshTool.PROP_OUT_STREAM, stdout)
-            .configure(SshTool.PROP_ERR_STREAM, stderr);
-        if (Boolean.TRUE.equals(execAsCommand)) {
-            exitStatus = machine.execCommands(flags.getAllConfig(),
-                    "ssh-feed", ImmutableList.of(command), env);
-        } else {
-            exitStatus = machine.execScript(flags.getAllConfig(),
-                    "ssh-feed", ImmutableList.of(command), env);
-        }
-
-        return new SshPollValue(machine, exitStatus, new String(stdout.toByteArray()), new String(stderr.toByteArray()));
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/ssh/SshPollConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/ssh/SshPollConfig.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/ssh/SshPollConfig.java
deleted file mode 100644
index b666d42..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/ssh/SshPollConfig.java
+++ /dev/null
@@ -1,142 +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.feed.ssh;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.sensor.feed.PollConfig;
-import org.apache.brooklyn.util.collections.MutableList;
-import org.apache.brooklyn.util.collections.MutableMap;
-
-import com.google.common.base.Preconditions;
-import com.google.common.base.Predicate;
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-
-public class SshPollConfig<T> extends PollConfig<SshPollValue, T, SshPollConfig<T>> {
-
-    private Supplier<String> commandSupplier;
-    private List<Supplier<Map<String,String>>> dynamicEnvironmentSupplier = MutableList.of();
-
-    public static final Predicate<SshPollValue> DEFAULT_SUCCESS = new Predicate<SshPollValue>() {
-        @Override
-        public boolean apply(@Nullable SshPollValue input) {
-            return input != null && input.getExitStatus() == 0;
-        }};
-
-    public SshPollConfig(AttributeSensor<T> sensor) {
-        super(sensor);
-        super.checkSuccess(DEFAULT_SUCCESS);
-    }
-
-    public SshPollConfig(SshPollConfig<T> other) {
-        super(other);
-        commandSupplier = other.commandSupplier;
-    }
-    
-    /** @deprecated since 0.7.0; use {@link #getCommandSupplier()} and resolve just-in-time */
-    public String getCommand() {
-        return getCommandSupplier().get();
-    }
-    public Supplier<String> getCommandSupplier() {
-        return commandSupplier;
-    }
-    
-    /** @deprecated since 0.7.0; use {@link #getEnvSupplier()} and resolve just-in-time */
-    public Map<String, String> getEnv() {
-        return getEnvSupplier().get();
-    }
-    public Supplier<Map<String,String>> getEnvSupplier() {
-        return new Supplier<Map<String,String>>() {
-            @Override
-            public Map<String, String> get() {
-                Map<String,String> result = MutableMap.of();
-                for (Supplier<Map<String, String>> envS: dynamicEnvironmentSupplier) {
-                    if (envS!=null) {
-                        Map<String, String> envM = envS.get();
-                        if (envM!=null) {
-                            mergeEnvMaps(envM, result);
-                        }
-                    }
-                }
-                return result;
-            }
-        };
-    }
-    
-    protected void mergeEnvMaps(Map<String,String> supplied, Map<String,String> target) {
-        if (supplied==null) return;
-        // as the value is a string there is no need to look at deep merge behaviour
-        target.putAll(supplied);
-    }
-
-    public SshPollConfig<T> command(String val) { return command(Suppliers.ofInstance(val)); }
-    public SshPollConfig<T> command(Supplier<String> val) {
-        this.commandSupplier = val;
-        return this;
-    }
-
-    /** add the given env param; sequence is as per {@link #env(Supplier)} */
-    public SshPollConfig<T> env(String key, String val) {
-        return env(Collections.singletonMap(key, val));
-    }
-    
-    /** add the given env params; sequence is as per {@link #env(Supplier)}.
-     * behaviour is undefined if the map supplied here is subsequently changed.
-     * <p>
-     * if a map's contents might change, use {@link #env(Supplier)} */
-    public SshPollConfig<T> env(Map<String,String> val) {
-        if (val==null) return this;
-        return env(Suppliers.ofInstance(val));
-    }
-
-    /** 
-     * adds the given dynamic supplier of environment variables.
-     * <p>
-     * use of a supplier allows env vars to be computed on each execution,
-     * for example to take the most recent sensor values.
-     * <p>
-     * in the case of multiple map suppliers, static maps, or static {@link #env(String, String)} 
-     * key value pairs, the order in which they are specified here is the order
-     * in which they are computed and applied. 
-     **/
-    public SshPollConfig<T> env(Supplier<Map<String,String>> val) {
-        Preconditions.checkNotNull(val);
-        dynamicEnvironmentSupplier.add(val);
-        return this;
-    }
-
-    @Override protected String toStringBaseName() { return "ssh"; }
-    @Override protected Object toStringPollSource() {
-        if (getCommandSupplier()==null) return null;
-        String command = getCommandSupplier().get();
-        return command;
-    }
-    @Override protected MutableList<Object> equalsFields() { 
-        return super.equalsFields()
-            .appendIfNotNull(getCommandSupplier()!=null ? getCommandSupplier().get() : null)
-            .appendIfNotNull(getEnvSupplier()!=null ? getEnvSupplier().get() : null); 
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/ssh/SshPollValue.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/ssh/SshPollValue.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/ssh/SshPollValue.java
deleted file mode 100644
index 8f1885d..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/ssh/SshPollValue.java
+++ /dev/null
@@ -1,60 +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.feed.ssh;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.location.ssh.SshMachineLocation;
-
-public class SshPollValue {
-
-    private final SshMachineLocation machine;
-    private final int exitStatus;
-    private final String stdout;
-    private final String stderr;
-
-    public SshPollValue(SshMachineLocation machine, int exitStatus, String stdout, String stderr) {
-        this.machine = machine;
-        this.exitStatus = exitStatus;
-        this.stdout = stdout;
-        this.stderr = stderr;
-    }
-    
-    /** The machine the command will run on. */
-    public SshMachineLocation getMachine() {
-        return machine;
-    }
-
-    /** Command exit status, or -1 if error is set. */
-    public int getExitStatus() {
-        return exitStatus;
-    }
-
-    /** Command standard output; may be null if no content available. */
-    @Nullable
-    public String getStdout() {
-        return stdout;
-    }
-
-    /** Command standard error; may be null if no content available. */
-    @Nullable
-    public String getStderr() {
-        return stderr;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/ssh/SshValueFunctions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/ssh/SshValueFunctions.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/ssh/SshValueFunctions.java
deleted file mode 100644
index 9ef3048..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/ssh/SshValueFunctions.java
+++ /dev/null
@@ -1,73 +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.feed.ssh;
-
-import javax.annotation.Nullable;
-
-import com.google.common.base.Function;
-import com.google.common.base.Functions;
-import com.google.common.base.Predicates;
-
-public class SshValueFunctions {
-
-    public static Function<SshPollValue, Integer> exitStatus() {
-        return new Function<SshPollValue, Integer>() {
-            @Override public Integer apply(SshPollValue input) {
-                return input.getExitStatus();
-            }
-        };
-    }
-
-    public static Function<SshPollValue, String> stdout() {
-        return new Function<SshPollValue, String>() {
-            @Override public String apply(SshPollValue input) {
-                return input.getStdout();
-            }
-        };
-    }
-    
-    public static Function<SshPollValue, String> stderr() {
-        return new Function<SshPollValue, String>() {
-            @Override public String apply(SshPollValue input) {
-                return input.getStderr();
-            }
-        };
-    }
-    
-    public static Function<SshPollValue, Boolean> exitStatusEquals(final int expected) {
-        return chain(SshValueFunctions.exitStatus(), Functions.forPredicate(Predicates.equalTo(expected)));
-    }
-
-    // TODO Do we want these chain methods? Does guava have them already? Duplicated in HttpValueFunctions.
-    public static <A,B,C> Function<A,C> chain(final Function<A,? extends B> f1, final Function<B,C> f2) {
-        return new Function<A,C>() {
-            @Override public C apply(@Nullable A input) {
-                return f2.apply(f1.apply(input));
-            }
-        };
-    }
-    
-    public static <A,B,C,D> Function<A,D> chain(final Function<A,? extends B> f1, final Function<B,? extends C> f2, final Function<C,D> f3) {
-        return new Function<A,D>() {
-            @Override public D apply(@Nullable A input) {
-                return f3.apply(f2.apply(f1.apply(input)));
-            }
-        };
-    }
-}


[17/36] incubator-brooklyn git commit: Rename o.a.b.sensor.feed to o.a.b.feed and o.a.b.core.feed

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java
index 01fde1f..5f55ae8 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java
@@ -30,11 +30,11 @@ import org.apache.brooklyn.entity.chef.ChefConfig;
 import org.apache.brooklyn.entity.chef.ChefLifecycleEffectorTasks;
 import org.apache.brooklyn.entity.chef.ChefServerTasks;
 import org.apache.brooklyn.entity.stock.EffectorStartableImpl;
+import org.apache.brooklyn.feed.ssh.SshFeed;
+import org.apache.brooklyn.feed.ssh.SshPollConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.feed.ssh.SshFeed;
-import org.apache.brooklyn.sensor.feed.ssh.SshPollConfig;
 import org.apache.brooklyn.util.collections.Jsonya;
 import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.core.config.ConfigBag;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQBrokerImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQBrokerImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQBrokerImpl.java
index a22e9e0..3e9dd2b 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQBrokerImpl.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQBrokerImpl.java
@@ -27,8 +27,8 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.entity.messaging.jms.JMSBrokerImpl;
-import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;
-import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
+import org.apache.brooklyn.feed.jmx.JmxAttributePollConfig;
+import org.apache.brooklyn.feed.jmx.JmxFeed;
 
 import com.google.common.base.Functions;
 import com.google.common.base.Objects.ToStringHelper;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQDestinationImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQDestinationImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQDestinationImpl.java
index 28375a0..6a27030 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQDestinationImpl.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQDestinationImpl.java
@@ -27,8 +27,8 @@ import org.apache.brooklyn.api.entity.EntityLocal;
 import com.google.common.base.Preconditions;
 
 import org.apache.brooklyn.entity.messaging.jms.JMSDestinationImpl;
-import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
-import org.apache.brooklyn.sensor.feed.jmx.JmxHelper;
+import org.apache.brooklyn.feed.jmx.JmxFeed;
+import org.apache.brooklyn.feed.jmx.JmxHelper;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 
 public abstract class ActiveMQDestinationImpl extends JMSDestinationImpl implements ActiveMQDestination {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQQueueImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQQueueImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQQueueImpl.java
index dddb6c9..daa121e 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQQueueImpl.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQQueueImpl.java
@@ -18,8 +18,8 @@
  */
 package org.apache.brooklyn.entity.messaging.activemq;
 
-import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;
-import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
+import org.apache.brooklyn.feed.jmx.JmxAttributePollConfig;
+import org.apache.brooklyn.feed.jmx.JmxFeed;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaBrokerImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaBrokerImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaBrokerImpl.java
index a0563b7..56db260 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaBrokerImpl.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaBrokerImpl.java
@@ -30,9 +30,9 @@ import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.entity.messaging.MessageBroker;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
 import org.apache.brooklyn.entity.zookeeper.ZooKeeperNode;
-import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;
-import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
-import org.apache.brooklyn.sensor.feed.jmx.JmxHelper;
+import org.apache.brooklyn.feed.jmx.JmxAttributePollConfig;
+import org.apache.brooklyn.feed.jmx.JmxFeed;
+import org.apache.brooklyn.feed.jmx.JmxHelper;
 
 import com.google.common.base.Functions;
 import com.google.common.base.Objects.ToStringHelper;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaClusterImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaClusterImpl.java
index dff0728..ceb4422 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaClusterImpl.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaClusterImpl.java
@@ -27,12 +27,12 @@ import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.feed.ConfigToAttributes;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.entity.group.DynamicCluster;
 import org.apache.brooklyn.entity.zookeeper.ZooKeeperNode;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
-import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.exceptions.CompoundRuntimeException;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidBrokerImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidBrokerImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidBrokerImpl.java
index 19335d9..72e6280 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidBrokerImpl.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidBrokerImpl.java
@@ -33,9 +33,9 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.entity.java.JmxSupport;
 import org.apache.brooklyn.entity.messaging.jms.JMSBrokerImpl;
-import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;
-import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
-import org.apache.brooklyn.sensor.feed.jmx.JmxHelper;
+import org.apache.brooklyn.feed.jmx.JmxAttributePollConfig;
+import org.apache.brooklyn.feed.jmx.JmxFeed;
+import org.apache.brooklyn.feed.jmx.JmxHelper;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 
 import com.google.common.base.Function;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidDestinationImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidDestinationImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidDestinationImpl.java
index 61553bf..155e43a 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidDestinationImpl.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidDestinationImpl.java
@@ -29,8 +29,8 @@ import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.entity.messaging.amqp.AmqpServer;
 import org.apache.brooklyn.entity.messaging.jms.JMSDestinationImpl;
-import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
-import org.apache.brooklyn.sensor.feed.jmx.JmxHelper;
+import org.apache.brooklyn.feed.jmx.JmxFeed;
+import org.apache.brooklyn.feed.jmx.JmxHelper;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidQueueImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidQueueImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidQueueImpl.java
index d1b81af..e9d6b95 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidQueueImpl.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidQueueImpl.java
@@ -24,8 +24,8 @@ import javax.management.MalformedObjectNameException;
 import javax.management.ObjectName;
 
 import org.apache.brooklyn.entity.messaging.amqp.AmqpExchange;
-import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;
-import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
+import org.apache.brooklyn.feed.jmx.JmxAttributePollConfig;
+import org.apache.brooklyn.feed.jmx.JmxFeed;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 
 public class QpidQueueImpl extends QpidDestinationImpl implements QpidQueue {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitQueue.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitQueue.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitQueue.java
index ae84f60..037085b 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitQueue.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitQueue.java
@@ -19,9 +19,9 @@
 package org.apache.brooklyn.entity.messaging.rabbit;
 
 import org.apache.brooklyn.entity.messaging.Queue;
-import org.apache.brooklyn.sensor.feed.ssh.SshFeed;
-import org.apache.brooklyn.sensor.feed.ssh.SshPollConfig;
-import org.apache.brooklyn.sensor.feed.ssh.SshPollValue;
+import org.apache.brooklyn.feed.ssh.SshFeed;
+import org.apache.brooklyn.feed.ssh.SshPollConfig;
+import org.apache.brooklyn.feed.ssh.SshPollValue;
 
 import com.google.common.base.Function;
 import com.google.common.base.Functions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormImpl.java
index 38b8ac0..a1fc3d8 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormImpl.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormImpl.java
@@ -24,8 +24,8 @@ import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.entity.java.JavaAppUtils;
 import org.apache.brooklyn.entity.java.JavaSoftwareProcessDriver;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
-import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
-import org.apache.brooklyn.sensor.feed.jmx.JmxHelper;
+import org.apache.brooklyn.feed.jmx.JmxFeed;
+import org.apache.brooklyn.feed.jmx.JmxHelper;
 import org.apache.brooklyn.util.time.Duration;
 import org.apache.brooklyn.util.time.Time;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/AbstractZooKeeperImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/AbstractZooKeeperImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/AbstractZooKeeperImpl.java
index f0d4872..60175c9 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/AbstractZooKeeperImpl.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/AbstractZooKeeperImpl.java
@@ -24,9 +24,9 @@ import javax.management.ObjectName;
 
 import org.apache.brooklyn.entity.java.JavaSoftwareProcessDriver;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
-import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;
-import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
-import org.apache.brooklyn.sensor.feed.jmx.JmxHelper;
+import org.apache.brooklyn.feed.jmx.JmxAttributePollConfig;
+import org.apache.brooklyn.feed.jmx.JmxFeed;
+import org.apache.brooklyn.feed.jmx.JmxHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/monit/MonitNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/monit/MonitNodeImpl.java b/software/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/monit/MonitNodeImpl.java
index 8b5914c..5af6dff 100644
--- a/software/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/monit/MonitNodeImpl.java
+++ b/software/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/monit/MonitNodeImpl.java
@@ -23,10 +23,10 @@ import java.util.Map;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
+import org.apache.brooklyn.feed.ssh.SshFeed;
+import org.apache.brooklyn.feed.ssh.SshPollConfig;
+import org.apache.brooklyn.feed.ssh.SshPollValue;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.feed.ssh.SshFeed;
-import org.apache.brooklyn.sensor.feed.ssh.SshPollConfig;
-import org.apache.brooklyn.sensor.feed.ssh.SshPollValue;
 import org.apache.brooklyn.util.text.Strings;
 import org.apache.brooklyn.util.time.Duration;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeImpl.java
index d549776..b753df6 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeImpl.java
@@ -45,16 +45,16 @@ import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.java.JavaAppUtils;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
+import org.apache.brooklyn.feed.function.FunctionFeed;
+import org.apache.brooklyn.feed.function.FunctionPollConfig;
+import org.apache.brooklyn.feed.jmx.JmxAttributePollConfig;
+import org.apache.brooklyn.feed.jmx.JmxFeed;
+import org.apache.brooklyn.feed.jmx.JmxHelper;
+import org.apache.brooklyn.feed.jmx.JmxOperationPollConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.policy.enricher.RollingTimeWindowMeanEnricher;
 import org.apache.brooklyn.policy.enricher.TimeWeightedDeltaEnricher;
-import org.apache.brooklyn.sensor.feed.function.FunctionFeed;
-import org.apache.brooklyn.sensor.feed.function.FunctionPollConfig;
-import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;
-import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
-import org.apache.brooklyn.sensor.feed.jmx.JmxHelper;
-import org.apache.brooklyn.sensor.feed.jmx.JmxOperationPollConfig;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.text.TemplateProcessor;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
index c065897..4bff736 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
@@ -45,13 +45,13 @@ import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.entity.group.AbstractMembershipTrackingPolicy;
 import org.apache.brooklyn.entity.group.DynamicClusterImpl;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
+import org.apache.brooklyn.feed.http.JsonFunctions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
-import org.apache.brooklyn.sensor.feed.http.JsonFunctions;
 import org.apache.brooklyn.util.collections.CollectionFunctionals;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.collections.QuorumCheck;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeImpl.java
index bed5a3d..74deb3e 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeImpl.java
@@ -35,13 +35,13 @@ import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
 import org.apache.brooklyn.core.location.cloud.CloudLocationConfig;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
+import org.apache.brooklyn.feed.http.JsonFunctions;
 import org.apache.http.auth.UsernamePasswordCredentials;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
-import org.apache.brooklyn.sensor.feed.http.JsonFunctions;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.config.ConfigBag;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
index 5da3c47..cc21867 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
@@ -42,9 +42,9 @@ import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
 import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.entity.software.base.AbstractSoftwareProcessSshDriver;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
 import org.apache.http.auth.UsernamePasswordCredentials;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.http.HttpTool;
 import org.apache.brooklyn.util.core.http.HttpToolResponse;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayImpl.java
index 724f246..c2e0395 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayImpl.java
@@ -21,9 +21,9 @@ package org.apache.brooklyn.entity.nosql.couchbase;
 import org.apache.brooklyn.core.config.render.RendererHints;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
 
 import com.google.common.base.Functions;
 import com.google.common.net.HostAndPort;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchdb/CouchDBNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchdb/CouchDBNodeImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchdb/CouchDBNodeImpl.java
index 163e126..06078f8 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchdb/CouchDBNodeImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchdb/CouchDBNodeImpl.java
@@ -25,9 +25,9 @@ import javax.annotation.Nullable;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
 import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcessImpl;
 import org.apache.brooklyn.entity.webapp.WebAppServiceMethods;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
 import org.apache.brooklyn.util.core.flags.TypeCoercions;
 import org.apache.brooklyn.util.guava.Functionals;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchNodeImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchNodeImpl.java
index b2cb577..413b82c 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchNodeImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchNodeImpl.java
@@ -23,10 +23,10 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
-import org.apache.brooklyn.sensor.feed.http.JsonFunctions;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
+import org.apache.brooklyn.feed.http.JsonFunctions;
 import org.apache.brooklyn.util.core.http.HttpToolResponse;
 import org.apache.brooklyn.util.guava.Functionals;
 import org.apache.brooklyn.util.guava.Maybe;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBServerImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBServerImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBServerImpl.java
index de56c8a..ea9c406 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBServerImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBServerImpl.java
@@ -27,11 +27,11 @@ import org.apache.brooklyn.api.sensor.SensorEventListener;
 import org.apache.brooklyn.core.config.render.RendererHints;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
+import org.apache.brooklyn.feed.function.FunctionFeed;
+import org.apache.brooklyn.feed.function.FunctionPollConfig;
 import org.bson.BasicBSONObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.apache.brooklyn.sensor.feed.function.FunctionFeed;
-import org.apache.brooklyn.sensor.feed.function.FunctionPollConfig;
 
 import com.google.common.base.Functions;
 import com.google.common.base.Objects;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBRouterImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBRouterImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBRouterImpl.java
index 5698ee6..149457d 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBRouterImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBRouterImpl.java
@@ -23,8 +23,8 @@ import java.util.concurrent.TimeUnit;
 
 import org.apache.brooklyn.entity.nosql.mongodb.MongoDBClientSupport;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
-import org.apache.brooklyn.sensor.feed.function.FunctionFeed;
-import org.apache.brooklyn.sensor.feed.function.FunctionPollConfig;
+import org.apache.brooklyn.feed.function.FunctionFeed;
+import org.apache.brooklyn.feed.function.FunctionPollConfig;
 
 import com.google.common.base.Functions;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisStoreImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisStoreImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisStoreImpl.java
index 857c048..5b35c63 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisStoreImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisStoreImpl.java
@@ -27,11 +27,11 @@ import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
+import org.apache.brooklyn.feed.ssh.SshFeed;
+import org.apache.brooklyn.feed.ssh.SshPollConfig;
+import org.apache.brooklyn.feed.ssh.SshPollValue;
+import org.apache.brooklyn.feed.ssh.SshValueFunctions;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.feed.ssh.SshFeed;
-import org.apache.brooklyn.sensor.feed.ssh.SshPollConfig;
-import org.apache.brooklyn.sensor.feed.ssh.SshPollValue;
-import org.apache.brooklyn.sensor.feed.ssh.SshValueFunctions;
 
 import com.google.common.base.Function;
 import com.google.common.base.Functions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeImpl.java
index 090f36d..85ac3e8 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeImpl.java
@@ -35,10 +35,10 @@ import org.apache.brooklyn.core.location.cloud.CloudLocationConfig;
 import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
 import org.apache.brooklyn.entity.webapp.WebAppServiceMethods;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.guava.Functionals;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/solr/SolrServerImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/solr/SolrServerImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/solr/SolrServerImpl.java
index 903fc58..3ee54fe 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/solr/SolrServerImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/solr/SolrServerImpl.java
@@ -21,9 +21,9 @@ package org.apache.brooklyn.entity.nosql.solr;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
 
 import com.google.common.base.Functions;
 import com.google.common.net.HostAndPort;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchClusterIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchClusterIntegrationTest.java b/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchClusterIntegrationTest.java
index e25aef6..211c754 100644
--- a/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchClusterIntegrationTest.java
+++ b/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchClusterIntegrationTest.java
@@ -31,7 +31,7 @@ import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.core.http.HttpTool;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchNodeIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchNodeIntegrationTest.java b/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchNodeIntegrationTest.java
index 7437d7a..a908886 100644
--- a/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchNodeIntegrationTest.java
+++ b/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchNodeIntegrationTest.java
@@ -30,7 +30,7 @@ import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.core.http.HttpTool;
 import org.apache.brooklyn.util.core.http.HttpToolResponse;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerImpl.java
----------------------------------------------------------------------
diff --git a/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerImpl.java b/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerImpl.java
index a864f6c..7051b86 100644
--- a/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerImpl.java
+++ b/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerImpl.java
@@ -37,13 +37,13 @@ import org.apache.brooklyn.api.sensor.SensorEvent;
 import org.apache.brooklyn.api.sensor.SensorEventListener;
 import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.annotation.EffectorParam;
+import org.apache.brooklyn.core.feed.ConfigToAttributes;
 import org.apache.brooklyn.entity.java.JmxSupport;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
-import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
-import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;
-import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
-import org.apache.brooklyn.sensor.feed.jmx.JmxHelper;
-import org.apache.brooklyn.sensor.feed.jmx.JmxValueFunctions;
+import org.apache.brooklyn.feed.jmx.JmxAttributePollConfig;
+import org.apache.brooklyn.feed.jmx.JmxFeed;
+import org.apache.brooklyn.feed.jmx.JmxHelper;
+import org.apache.brooklyn.feed.jmx.JmxValueFunctions;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.os.Os;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/AbstractControllerImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/AbstractControllerImpl.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/AbstractControllerImpl.java
index b98779e..ec3e714 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/AbstractControllerImpl.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/AbstractControllerImpl.java
@@ -38,6 +38,7 @@ import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.feed.ConfigToAttributes;
 import org.apache.brooklyn.core.location.Machines;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
 import org.apache.brooklyn.entity.group.AbstractMembershipTrackingPolicy;
@@ -45,7 +46,6 @@ import org.apache.brooklyn.entity.group.Cluster;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.task.Tasks;
 import org.apache.brooklyn.util.exceptions.Exceptions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/AbstractNonProvisionedControllerImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/AbstractNonProvisionedControllerImpl.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/AbstractNonProvisionedControllerImpl.java
index cbbd115..7996444 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/AbstractNonProvisionedControllerImpl.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/AbstractNonProvisionedControllerImpl.java
@@ -32,9 +32,9 @@ import org.apache.brooklyn.api.policy.PolicySpec;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.feed.ConfigToAttributes;
 import org.apache.brooklyn.entity.group.AbstractMembershipTrackingPolicy;
 import org.apache.brooklyn.entity.group.Cluster;
-import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxControllerImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxControllerImpl.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxControllerImpl.java
index e1f67c3..7952c91 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxControllerImpl.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxControllerImpl.java
@@ -35,15 +35,15 @@ import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceNotUpLogic;
+import org.apache.brooklyn.core.feed.ConfigToAttributes;
 import org.apache.brooklyn.entity.group.AbstractMembershipTrackingPolicy;
 import org.apache.brooklyn.entity.proxy.AbstractControllerImpl;
 import org.apache.brooklyn.entity.proxy.ProxySslConfig;
 import org.apache.brooklyn.entity.proxy.nginx.NginxController.NginxControllerInternal;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
-import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
 import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.core.file.ArchiveUtils;
 import org.apache.brooklyn.util.core.http.HttpTool;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
index 74cb01c..7ff08a5 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
@@ -37,12 +37,12 @@ import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.entity.trait.StartableMethods;
+import org.apache.brooklyn.core.feed.ConfigToAttributes;
 import org.apache.brooklyn.entity.group.DynamicGroupImpl;
 import org.apache.brooklyn.entity.proxy.LoadBalancer;
 import org.apache.brooklyn.entity.proxy.nginx.NginxController;
 import org.apache.brooklyn.entity.webapp.tomcat.TomcatServer;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
-import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.QuorumCheck.QuorumChecks;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6ServerImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6ServerImpl.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6ServerImpl.java
index e5e7696..7c7173b 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6ServerImpl.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6ServerImpl.java
@@ -25,9 +25,9 @@ import java.util.concurrent.TimeUnit;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcessImpl;
+import org.apache.brooklyn.feed.jmx.JmxAttributePollConfig;
+import org.apache.brooklyn.feed.jmx.JmxFeed;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
-import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;
-import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerImpl.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerImpl.java
index f58c40a..f32d6a0 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerImpl.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerImpl.java
@@ -25,12 +25,12 @@ import org.apache.brooklyn.core.config.render.RendererHints;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
 import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcessImpl;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
 import org.apache.brooklyn.util.guava.Functionals;
 
 import com.google.common.base.Functions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jetty/Jetty6ServerImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jetty/Jetty6ServerImpl.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jetty/Jetty6ServerImpl.java
index a6862fa..d264c66 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jetty/Jetty6ServerImpl.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jetty/Jetty6ServerImpl.java
@@ -24,9 +24,9 @@ import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.entity.java.JavaAppUtils;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcessImpl;
+import org.apache.brooklyn.feed.jmx.JmxAttributePollConfig;
+import org.apache.brooklyn.feed.jmx.JmxFeed;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
-import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;
-import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppServiceImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppServiceImpl.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppServiceImpl.java
index bd5b873..d72b6db 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppServiceImpl.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppServiceImpl.java
@@ -19,15 +19,15 @@
 package org.apache.brooklyn.entity.webapp.nodejs;
 
 import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.feed.ConfigToAttributes;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
 import org.apache.brooklyn.entity.webapp.WebAppServiceMethods;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
 
 import com.google.common.base.Predicates;
 import com.google.common.net.HostAndPort;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/tomcat/TomcatServerImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/tomcat/TomcatServerImpl.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/tomcat/TomcatServerImpl.java
index a55fa44..22cab1f 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/tomcat/TomcatServerImpl.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/tomcat/TomcatServerImpl.java
@@ -24,8 +24,8 @@ import java.util.concurrent.TimeUnit;
 
 import org.apache.brooklyn.entity.java.JavaAppUtils;
 import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcessImpl;
-import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;
-import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
+import org.apache.brooklyn.feed.jmx.JmxAttributePollConfig;
+import org.apache.brooklyn.feed.jmx.JmxFeed;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedJBoss7ServerImpl.java
----------------------------------------------------------------------
diff --git a/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedJBoss7ServerImpl.java b/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedJBoss7ServerImpl.java
index 856306e..05f40ed 100644
--- a/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedJBoss7ServerImpl.java
+++ b/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedJBoss7ServerImpl.java
@@ -27,13 +27,13 @@ import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
 import org.apache.brooklyn.entity.webapp.jboss.JBoss7ServerImpl;
 import org.apache.brooklyn.entity.webapp.jboss.JBoss7SshDriver;
+import org.apache.brooklyn.feed.function.FunctionFeed;
+import org.apache.brooklyn.feed.function.FunctionPollConfig;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
-import org.apache.brooklyn.sensor.feed.function.FunctionFeed;
-import org.apache.brooklyn.sensor.feed.function.FunctionPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.guava.Functionals;
 import org.apache.brooklyn.util.os.Os;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedMySqlNodeImpl.java
----------------------------------------------------------------------
diff --git a/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedMySqlNodeImpl.java b/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedMySqlNodeImpl.java
index 34c8ba4..30da612 100644
--- a/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedMySqlNodeImpl.java
+++ b/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedMySqlNodeImpl.java
@@ -28,9 +28,9 @@ import org.apache.brooklyn.entity.database.mysql.MySqlNode;
 import org.apache.brooklyn.entity.database.mysql.MySqlNodeImpl;
 import org.apache.brooklyn.entity.database.mysql.MySqlSshDriver;
 import org.apache.brooklyn.entity.software.base.AbstractSoftwareProcessSshDriver;
+import org.apache.brooklyn.feed.function.FunctionFeed;
+import org.apache.brooklyn.feed.function.FunctionPollConfig;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.feed.function.FunctionFeed;
-import org.apache.brooklyn.sensor.feed.function.FunctionPollConfig;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
 import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedNginxControllerImpl.java
----------------------------------------------------------------------
diff --git a/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedNginxControllerImpl.java b/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedNginxControllerImpl.java
index 258da82..d57bf63 100644
--- a/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedNginxControllerImpl.java
+++ b/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedNginxControllerImpl.java
@@ -29,15 +29,15 @@ import org.apache.brooklyn.api.policy.PolicySpec;
 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.feed.ConfigToAttributes;
 import org.apache.brooklyn.entity.proxy.nginx.NginxControllerImpl;
 import org.apache.brooklyn.entity.proxy.nginx.NginxSshDriver;
 import org.apache.brooklyn.entity.proxy.nginx.UrlMapping;
+import org.apache.brooklyn.feed.function.FunctionFeed;
+import org.apache.brooklyn.feed.function.FunctionPollConfig;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
-import org.apache.brooklyn.sensor.feed.function.FunctionFeed;
-import org.apache.brooklyn.sensor.feed.function.FunctionPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.net.Networking;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/usage/rest-server/src/test/java/org/apache/brooklyn/rest/test/entity/brooklynnode/DeployBlueprintTest.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/test/entity/brooklynnode/DeployBlueprintTest.java b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/test/entity/brooklynnode/DeployBlueprintTest.java
index 6750add..2a464f2 100644
--- a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/test/entity/brooklynnode/DeployBlueprintTest.java
+++ b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/test/entity/brooklynnode/DeployBlueprintTest.java
@@ -30,8 +30,8 @@ import org.apache.brooklyn.api.mgmt.EntityManager;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNode.DeployBlueprintEffector;
 import org.apache.brooklyn.entity.stock.BasicApplication;
+import org.apache.brooklyn.feed.http.JsonFunctions;
 import org.apache.brooklyn.rest.BrooklynRestApiLauncherTestFixture;
-import org.apache.brooklyn.sensor.feed.http.JsonFunctions;
 import org.apache.brooklyn.test.HttpTestUtils;
 import org.apache.brooklyn.util.guava.Functionals;
 import org.eclipse.jetty.server.Server;


[34/36] incubator-brooklyn git commit: Rename o.a.b.sensor.enricher to o.a.b.core.enricher

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/enricher/stock/Combiner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/Combiner.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/Combiner.java
new file mode 100644
index 0000000..6819a33
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/Combiner.java
@@ -0,0 +1,138 @@
+/*
+ * 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.enricher.stock;
+
+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.enricher.AbstractEnricher;
+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/enricher/stock/CustomAggregatingEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/CustomAggregatingEnricher.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/CustomAggregatingEnricher.java
new file mode 100644
index 0000000..0a03dca
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/CustomAggregatingEnricher.java
@@ -0,0 +1,320 @@
+/*
+ * 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.enricher.stock;
+
+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/enricher/stock/Enrichers.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/Enrichers.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/Enrichers.java
new file mode 100644
index 0000000..baed4f1
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/Enrichers.java
@@ -0,0 +1,825 @@
+/*
+ * 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.enricher.stock;
+
+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.core.enricher.AbstractEnricher;
+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.enricher.stock.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/enricher/stock/Joiner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/Joiner.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/Joiner.java
new file mode 100644
index 0000000..5cd2071
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/Joiner.java
@@ -0,0 +1,127 @@
+/*
+ * 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.enricher.stock;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.api.sensor.SensorEvent;
+import org.apache.brooklyn.api.sensor.SensorEventListener;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
+import org.apache.brooklyn.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/enricher/stock/Propagator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/Propagator.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/Propagator.java
new file mode 100644
index 0000000..e6050fd
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/Propagator.java
@@ -0,0 +1,201 @@
+/*
+ * 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.enricher.stock;
+
+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.enricher.AbstractEnricher;
+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;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/enricher/stock/SensorPropagatingEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/SensorPropagatingEnricher.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/SensorPropagatingEnricher.java
new file mode 100644
index 0000000..4c198f8
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/SensorPropagatingEnricher.java
@@ -0,0 +1,181 @@
+/*
+ * 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.enricher.stock;
+
+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.core.enricher.AbstractEnricher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+
+/** 
+ * an enricher policy which just listens for the target sensor(s) on a child entity and passes it up.
+ * now superseded by syntax such as:
+ * 
+ * <pre>{@code Enrichers.builder().propagating(XXX).from(source).build()}</pre>
+ * 
+ * @deprecated since 0.7.0; use {@link Enrichers#builder()}
+ * 
+ * @see Propagator if need to sub-class
+ */
+public class SensorPropagatingEnricher extends AbstractEnricher implements SensorEventListener<Object> {
+    
+    public static final Logger log = LoggerFactory.getLogger(SensorPropagatingEnricher.class);
+        
+    /** the entity to listen to */
+    private final Entity source;
+    
+    /** the sensors to listen to */
+    private final Set<Sensor<?>> sensors;
+
+    /** the sensors to listen to */
+    private final Map<Sensor<?>, Sensor<?>> sensorMappings;
+
+    public static SensorPropagatingEnricher newInstanceListeningToAllSensors(Entity source) {
+        return newInstanceListeningToAllSensorsBut(source);
+    }
+    public static SensorPropagatingEnricher newInstanceListeningToAllSensorsBut(Entity source, Sensor<?>... excludes) {
+        Set<Sensor<?>> excluded = ImmutableSet.copyOf(excludes);
+        Set<Sensor<?>> includes = Sets.newLinkedHashSet();
+        
+        for (Sensor<?> it : source.getEntityType().getSensors()) {
+            if (!excluded.contains(it)) includes.add(it);
+        }
+        return new SensorPropagatingEnricher(source, includes);
+    }
+
+    public static SensorPropagatingEnricher newInstanceListeningTo(Entity source, Sensor<?>... includes) {
+        return new SensorPropagatingEnricher(source, includes);
+    }
+
+    /**
+     * listens to sensors from source, propagates them here renamed according to the map
+     * 
+     * Instead, consider calling:
+     * <pre>
+     * {@code
+     * addEnricher(Enrichers.builder()
+     *         .propagating(mapOfOldSensorNamesToNewSensorNames)
+     *         .from(source)
+     *         .build());
+     * }
+     * </pre>
+     *
+     * @deprecated since 0.7.0; use {@link Enrichers#builder()}
+     */
+    public static SensorPropagatingEnricher newInstanceRenaming(Entity source, Map<? extends Sensor<?>, ? extends Sensor<?>> sensors) {
+        return new SensorPropagatingEnricher(source, sensors);
+    }
+
+    /**
+     * @deprecated since 0.7.0; use {@link Enrichers#builder()}
+     */
+    public SensorPropagatingEnricher(Entity source, Sensor<?>... sensors) {
+        this(source, ImmutableList.copyOf(sensors));
+    }
+    
+    /** 
+     * Instead, consider calling:
+     * <pre>
+     * {@code
+     * addEnricher(Enrichers.builder()
+     *         .propagating(sensors)
+     *         .from(source)
+     *         .build());
+     * }
+     * </pre>
+     *
+     * @deprecated since 0.7.0; use {@link Enrichers#builder()}
+     */
+    public SensorPropagatingEnricher(Entity source, Collection<Sensor<?>> sensors) {
+        this.source = source;
+        this.sensors = ImmutableSet.copyOf(sensors);
+        this.sensorMappings = ImmutableMap.of();
+    }
+    
+    public SensorPropagatingEnricher(Entity source, Map<? extends Sensor<?>, ? extends Sensor<?>> sensors) {
+        this.source = source;
+        this.sensors = ImmutableSet.copyOf(sensors.keySet());
+        this.sensorMappings = ImmutableMap.copyOf(sensors);
+    }
+    
+    public void setEntity(EntityLocal entity) {
+        super.setEntity(entity);
+        for (Sensor<?> s: sensors) {
+            subscribe(source, s, this);
+        }
+    }
+    
+    @Override
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public void onEvent(SensorEvent<Object> event) {
+        // propagate upwards
+        Sensor<?> sourceSensor = event.getSensor();
+        Sensor<?> destinationSensor = getDestinationSensor(sourceSensor);
+        
+        if (log.isTraceEnabled()) log.trace("policy {} got {}, propagating via {}{}", 
+                new Object[] {this, event, entity, (sourceSensor == destinationSensor ? "" : " (as "+destinationSensor+")")});
+        
+        if (event.getSensor() instanceof AttributeSensor) {
+            entity.setAttribute((AttributeSensor)destinationSensor, event.getValue());
+        } else {
+            entity.emit((Sensor)destinationSensor, event.getValue());
+        }       
+    }
+
+    /** useful post-addition to emit current values */
+    public void emitAllAttributes() {
+        emitAllAttributes(false);
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public void emitAllAttributes(boolean includeNullValues) {
+        for (Sensor s: sensors) {
+            if (s instanceof AttributeSensor) {
+                AttributeSensor destinationSensor = (AttributeSensor<?>) getDestinationSensor(s);
+                Object v = source.getAttribute((AttributeSensor)s);
+                if (v != null || includeNullValues) entity.setAttribute(destinationSensor, v);
+            }
+        }
+    }
+
+    /** convenience, to be called by the host */
+    public SensorPropagatingEnricher addToEntityAndEmitAll(Entity host) {
+        host.addEnricher(this);
+        emitAllAttributes();
+        return this;
+    }
+    
+    private Sensor<?> getDestinationSensor(Sensor<?> sourceSensor) {
+        return sensorMappings.containsKey(sourceSensor) ? sensorMappings.get(sourceSensor): sourceSensor;
+    }
+}


[26/36] incubator-brooklyn git commit: Rename o.a.b.sensor.feed to o.a.b.feed and o.a.b.core.feed

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/feed/http/HttpFeed.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/feed/http/HttpFeed.java b/core/src/main/java/org/apache/brooklyn/feed/http/HttpFeed.java
new file mode 100644
index 0000000..e8cfc9f
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/feed/http/HttpFeed.java
@@ -0,0 +1,382 @@
+/*
+ * 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.feed.http;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.net.URI;
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.feed.AbstractFeed;
+import org.apache.brooklyn.core.feed.AttributePollHandler;
+import org.apache.brooklyn.core.feed.DelegatingPollHandler;
+import org.apache.brooklyn.core.feed.Poller;
+import org.apache.brooklyn.util.core.http.HttpTool;
+import org.apache.brooklyn.util.core.http.HttpToolResponse;
+import org.apache.brooklyn.util.core.http.HttpTool.HttpClientBuilder;
+import org.apache.brooklyn.util.time.Duration;
+import org.apache.http.auth.Credentials;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.HttpClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Optional;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
+import com.google.common.reflect.TypeToken;
+
+/**
+ * Provides a feed of attribute values, by polling over http.
+ * 
+ * Example usage (e.g. in an entity that extends SoftwareProcessImpl):
+ * <pre>
+ * {@code
+ * private HttpFeed feed;
+ * 
+ * //@Override
+ * protected void connectSensors() {
+ *   super.connectSensors();
+ *   
+ *   feed = HttpFeed.builder()
+ *       .entity(this)
+ *       .period(200)
+ *       .baseUri(String.format("http://%s:%s/management/subsystem/web/connector/http/read-resource", host, port))
+ *       .baseUriVars(ImmutableMap.of("include-runtime","true"))
+ *       .poll(new HttpPollConfig<Boolean>(SERVICE_UP)
+ *           .onSuccess(HttpValueFunctions.responseCodeEquals(200))
+ *           .onError(Functions.constant(false)))
+ *       .poll(new HttpPollConfig<Integer>(REQUEST_COUNT)
+ *           .onSuccess(HttpValueFunctions.jsonContents("requestCount", Integer.class)))
+ *       .build();
+ * }
+ * 
+ * {@literal @}Override
+ * protected void disconnectSensors() {
+ *   super.disconnectSensors();
+ *   if (feed != null) feed.stop();
+ * }
+ * }
+ * </pre>
+ * <p>
+ *  
+ * This also supports giving a Supplier for the URL 
+ * (e.g. {@link Entities#attributeSupplier(org.apache.brooklyn.api.entity.Entity, org.apache.brooklyn.api.event.AttributeSensor)})
+ * from a sensor.  Note however that if a Supplier-based sensor is *https*,
+ * https-specific initialization may not occur if the URL is not available at start time,
+ * and it may report errors if that sensor is not available.
+ * Some guidance for controlling enablement of a feed based on availability of a sensor
+ * can be seen in HttpLatencyDetector (in brooklyn-policy). 
+ * 
+ * @author aled
+ */
+public class HttpFeed extends AbstractFeed {
+
+    public static final Logger log = LoggerFactory.getLogger(HttpFeed.class);
+
+    @SuppressWarnings("serial")
+    public static final ConfigKey<SetMultimap<HttpPollIdentifier, HttpPollConfig<?>>> POLLS = ConfigKeys.newConfigKey(
+            new TypeToken<SetMultimap<HttpPollIdentifier, HttpPollConfig<?>>>() {},
+            "polls");
+
+    public static Builder builder() {
+        return new Builder();
+    }
+    
+    public static class Builder {
+        private EntityLocal entity;
+        private boolean onlyIfServiceUp = false;
+        private Supplier<URI> baseUriProvider;
+        private Duration period = Duration.millis(500);
+        private List<HttpPollConfig<?>> polls = Lists.newArrayList();
+        private URI baseUri;
+        private Map<String, String> baseUriVars = Maps.newLinkedHashMap();
+        private Map<String, String> headers = Maps.newLinkedHashMap();
+        private boolean suspended = false;
+        private Credentials credentials;
+        private String uniqueTag;
+        private volatile boolean built;
+
+        public Builder entity(EntityLocal val) {
+            this.entity = val;
+            return this;
+        }
+        public Builder onlyIfServiceUp() { return onlyIfServiceUp(true); }
+        public Builder onlyIfServiceUp(boolean onlyIfServiceUp) { 
+            this.onlyIfServiceUp = onlyIfServiceUp; 
+            return this; 
+        }
+        public Builder baseUri(Supplier<URI> val) {
+            if (baseUri!=null && val!=null)
+                throw new IllegalStateException("Builder cannot take both a URI and a URI Provider");
+            this.baseUriProvider = val;
+            return this;
+        }
+        public Builder baseUri(URI val) {
+            if (baseUriProvider!=null && val!=null)
+                throw new IllegalStateException("Builder cannot take both a URI and a URI Provider");
+            this.baseUri = val;
+            return this;
+        }
+        public Builder baseUrl(URL val) {
+            return baseUri(URI.create(val.toString()));
+        }
+        public Builder baseUri(String val) {
+            return baseUri(URI.create(val));
+        }
+        public Builder baseUriVars(Map<String,String> vals) {
+            baseUriVars.putAll(vals);
+            return this;
+        }
+        public Builder baseUriVar(String key, String val) {
+            baseUriVars.put(key, val);
+            return this;
+        }
+        public Builder headers(Map<String,String> vals) {
+            headers.putAll(vals);
+            return this;
+        }
+        public Builder header(String key, String val) {
+            headers.put(key, val);
+            return this;
+        }
+        public Builder period(Duration duration) {
+            this.period = duration;
+            return this;
+        }
+        public Builder period(long millis) {
+            return period(millis, TimeUnit.MILLISECONDS);
+        }
+        public Builder period(long val, TimeUnit units) {
+            return period(Duration.of(val, units));
+        }
+        public Builder poll(HttpPollConfig<?> config) {
+            polls.add(config);
+            return this;
+        }
+        public Builder suspended() {
+            return suspended(true);
+        }
+        public Builder suspended(boolean startsSuspended) {
+            this.suspended = startsSuspended;
+            return this;
+        }
+        public Builder credentials(String username, String password) {
+            this.credentials = new UsernamePasswordCredentials(username, password);
+            return this;
+        }
+        public Builder credentialsIfNotNull(String username, String password) {
+            if (username != null && password != null) {
+                this.credentials = new UsernamePasswordCredentials(username, password);
+            }
+            return this;
+        }
+        public Builder uniqueTag(String uniqueTag) {
+            this.uniqueTag = uniqueTag;
+            return this;
+        }
+        public HttpFeed build() {
+            built = true;
+            HttpFeed result = new HttpFeed(this);
+            result.setEntity(checkNotNull(entity, "entity"));
+            if (suspended) result.suspend();
+            result.start();
+            return result;
+        }
+        @Override
+        protected void finalize() {
+            if (!built) log.warn("HttpFeed.Builder created, but build() never called");
+        }
+    }
+    
+    private static class HttpPollIdentifier {
+        final String method;
+        final Supplier<URI> uriProvider;
+        final Map<String,String> headers;
+        final byte[] body;
+        final Optional<Credentials> credentials;
+        final Duration connectionTimeout;
+        final Duration socketTimeout;
+        private HttpPollIdentifier(String method, Supplier<URI> uriProvider, Map<String, String> headers, byte[] body,
+                                   Optional<Credentials> credentials, Duration connectionTimeout, Duration socketTimeout) {
+            this.method = checkNotNull(method, "method").toLowerCase();
+            this.uriProvider = checkNotNull(uriProvider, "uriProvider");
+            this.headers = checkNotNull(headers, "headers");
+            this.body = body;
+            this.credentials = checkNotNull(credentials, "credentials");
+            this.connectionTimeout = connectionTimeout;
+            this.socketTimeout = socketTimeout;
+            
+            if (!(this.method.equals("get") || this.method.equals("post"))) {
+                throw new IllegalArgumentException("Unsupported HTTP method (only supports GET and POST): "+method);
+            }
+            if (body != null && method.equalsIgnoreCase("get")) {
+                throw new IllegalArgumentException("Must not set body for http GET method");
+            }
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(method, uriProvider, headers, body, credentials);
+        }
+        
+        @Override
+        public boolean equals(Object other) {
+            if (!(other instanceof HttpPollIdentifier)) {
+                return false;
+            }
+            HttpPollIdentifier o = (HttpPollIdentifier) other;
+            return Objects.equal(method, o.method) &&
+                    Objects.equal(uriProvider, o.uriProvider) &&
+                    Objects.equal(headers, o.headers) &&
+                    Objects.equal(body, o.body) &&
+                    Objects.equal(credentials, o.credentials);
+        }
+    }
+    
+    /**
+     * For rebind; do not call directly; use builder
+     */
+    public HttpFeed() {
+    }
+    
+    protected HttpFeed(Builder builder) {
+        setConfig(ONLY_IF_SERVICE_UP, builder.onlyIfServiceUp);
+        Map<String,String> baseHeaders = ImmutableMap.copyOf(checkNotNull(builder.headers, "headers"));
+        
+        SetMultimap<HttpPollIdentifier, HttpPollConfig<?>> polls = HashMultimap.<HttpPollIdentifier,HttpPollConfig<?>>create();
+        for (HttpPollConfig<?> config : builder.polls) {
+            if (!config.isEnabled()) continue;
+            @SuppressWarnings({ "unchecked", "rawtypes" })
+            HttpPollConfig<?> configCopy = new HttpPollConfig(config);
+            if (configCopy.getPeriod() < 0) configCopy.period(builder.period);
+            String method = config.getMethod();
+            Map<String,String> headers = config.buildHeaders(baseHeaders);
+            byte[] body = config.getBody();
+            Duration connectionTimeout = config.getConnectionTimeout();
+            Duration socketTimeout = config.getSocketTimeout();
+            
+            Optional<Credentials> credentials = Optional.fromNullable(builder.credentials);
+            
+            Supplier<URI> baseUriProvider = builder.baseUriProvider;
+            if (builder.baseUri!=null) {
+                if (baseUriProvider!=null)
+                    throw new IllegalStateException("Not permitted to supply baseUri and baseUriProvider");
+                Map<String,String> baseUriVars = ImmutableMap.copyOf(checkNotNull(builder.baseUriVars, "baseUriVars"));
+                URI uri = config.buildUri(builder.baseUri, baseUriVars);
+                baseUriProvider = Suppliers.ofInstance(uri);
+            } else if (!builder.baseUriVars.isEmpty()) {
+                throw new IllegalStateException("Not permitted to supply URI vars when using a URI provider; pass the vars to the provider instead");
+            }
+            checkNotNull(baseUriProvider);
+
+            polls.put(new HttpPollIdentifier(method, baseUriProvider, headers, body, credentials, connectionTimeout, socketTimeout), configCopy);
+        }
+        setConfig(POLLS, polls);
+        initUniqueTag(builder.uniqueTag, polls.values());
+    }
+
+    @Override
+    protected void preStart() {
+        SetMultimap<HttpPollIdentifier, HttpPollConfig<?>> polls = getConfig(POLLS);
+        
+        for (final HttpPollIdentifier pollInfo : polls.keySet()) {
+            // Though HttpClients are thread safe and can take advantage of connection pooling
+            // and authentication caching, the httpcomponents documentation says:
+            //    "While HttpClient instances are thread safe and can be shared between multiple
+            //     threads of execution, it is highly recommended that each thread maintains its
+            //     own dedicated instance of HttpContext.
+            //  http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html
+            final HttpClient httpClient = createHttpClient(pollInfo);
+
+            Set<HttpPollConfig<?>> configs = polls.get(pollInfo);
+            long minPeriod = Integer.MAX_VALUE;
+            Set<AttributePollHandler<? super HttpToolResponse>> handlers = Sets.newLinkedHashSet();
+
+            for (HttpPollConfig<?> config : configs) {
+                handlers.add(new AttributePollHandler<HttpToolResponse>(config, entity, this));
+                if (config.getPeriod() > 0) minPeriod = Math.min(minPeriod, config.getPeriod());
+            }
+
+            Callable<HttpToolResponse> pollJob;
+            
+            if (pollInfo.method.equals("get")) {
+                pollJob = new Callable<HttpToolResponse>() {
+                    public HttpToolResponse call() throws Exception {
+                        if (log.isTraceEnabled()) log.trace("http polling for {} sensors at {}", entity, pollInfo);
+                        return HttpTool.httpGet(httpClient, pollInfo.uriProvider.get(), pollInfo.headers);
+                    }};
+            } else if (pollInfo.method.equals("post")) {
+                pollJob = new Callable<HttpToolResponse>() {
+                    public HttpToolResponse call() throws Exception {
+                        if (log.isTraceEnabled()) log.trace("http polling for {} sensors at {}", entity, pollInfo);
+                        return HttpTool.httpPost(httpClient, pollInfo.uriProvider.get(), pollInfo.headers, pollInfo.body);
+                    }};
+            } else if (pollInfo.method.equals("head")) {
+                pollJob = new Callable<HttpToolResponse>() {
+                    public HttpToolResponse call() throws Exception {
+                        if (log.isTraceEnabled()) log.trace("http polling for {} sensors at {}", entity, pollInfo);
+                        return HttpTool.httpHead(httpClient, pollInfo.uriProvider.get(), pollInfo.headers);
+                    }};
+            } else {
+                throw new IllegalStateException("Unexpected http method: "+pollInfo.method);
+            }
+            
+            getPoller().scheduleAtFixedRate(pollJob, new DelegatingPollHandler<HttpToolResponse>(handlers), minPeriod);
+        }
+    }
+
+    // TODO Should we really trustAll for https? Make configurable?
+    private HttpClient createHttpClient(HttpPollIdentifier pollIdentifier) {
+        URI uri = pollIdentifier.uriProvider.get();
+        HttpClientBuilder builder = HttpTool.httpClientBuilder()
+                .trustAll()
+                .laxRedirect(true);
+        if (uri != null) builder.uri(uri);
+        if (uri != null) builder.credential(pollIdentifier.credentials);
+        if (pollIdentifier.connectionTimeout != null) {
+            builder.connectionTimeout(pollIdentifier.connectionTimeout);
+        }
+        if (pollIdentifier.socketTimeout != null) {
+            builder.socketTimeout(pollIdentifier.socketTimeout);
+        }
+        return builder.build();
+    }
+
+    @SuppressWarnings("unchecked")
+    protected Poller<HttpToolResponse> getPoller() {
+        return (Poller<HttpToolResponse>) super.getPoller();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/feed/http/HttpPollConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/feed/http/HttpPollConfig.java b/core/src/main/java/org/apache/brooklyn/feed/http/HttpPollConfig.java
new file mode 100644
index 0000000..e019293
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/feed/http/HttpPollConfig.java
@@ -0,0 +1,160 @@
+/*
+ * 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.feed.http;
+
+import java.net.URI;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.feed.PollConfig;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.http.HttpTool;
+import org.apache.brooklyn.util.core.http.HttpToolResponse;
+import org.apache.brooklyn.util.time.Duration;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMap;
+
+public class HttpPollConfig<T> extends PollConfig<HttpToolResponse, T, HttpPollConfig<T>> {
+
+    private String method = "GET";
+    private String suburl = "";
+    private Map<String, String> vars = ImmutableMap.<String,String>of();
+    private Map<String, String> headers = ImmutableMap.<String,String>of();
+    private byte[] body;
+    private Duration connectionTimeout;
+    private Duration socketTimeout;
+    
+    public static final Predicate<HttpToolResponse> DEFAULT_SUCCESS = new Predicate<HttpToolResponse>() {
+        @Override
+        public boolean apply(@Nullable HttpToolResponse input) {
+            return input != null && input.getResponseCode() >= 200 && input.getResponseCode() <= 399;
+        }};
+    
+    public static <T> HttpPollConfig<T> forSensor(AttributeSensor<T> sensor) {
+        return new HttpPollConfig<T>(sensor);
+    }
+    
+    public static HttpPollConfig<Void> forMultiple() {
+        return new HttpPollConfig<Void>(PollConfig.NO_SENSOR);
+    }
+    
+    public HttpPollConfig(AttributeSensor<T> sensor) {
+        super(sensor);
+        super.checkSuccess(DEFAULT_SUCCESS);
+    }
+
+    public HttpPollConfig(HttpPollConfig<T> other) {
+        super(other);
+        suburl = other.suburl;
+        vars = other.vars;
+        method = other.method;
+        headers = other.headers;
+    }
+    
+    public String getSuburl() {
+        return suburl;
+    }
+    
+    public Map<String, String> getVars() {
+        return vars;
+    }
+    
+    public Duration getConnectionTimeout() {
+        return connectionTimeout;
+    }
+    
+    public Duration getSocketTimeout() {
+        return socketTimeout;
+    }
+    
+    public String getMethod() {
+        return method;
+    }
+    
+    public byte[] getBody() {
+        return body;
+    }
+    
+    public HttpPollConfig<T> method(String val) {
+        this.method = val; return this;
+    }
+    
+    public HttpPollConfig<T> suburl(String val) {
+        this.suburl = val; return this;
+    }
+    
+    public HttpPollConfig<T> vars(Map<String,String> val) {
+        this.vars = val; return this;
+    }
+    
+    public HttpPollConfig<T> headers(Map<String,String> val) {
+        this.headers = val; return this;
+    }
+    
+    public HttpPollConfig<T> body(byte[] val) {
+        this.body = val; return this;
+    }
+    public HttpPollConfig<T> connectionTimeout(Duration val) {
+        this.connectionTimeout = val;
+        return this;
+    }
+    public HttpPollConfig<T> socketTimeout(Duration val) {
+        this.socketTimeout = val;
+        return this;
+    }
+    public URI buildUri(URI baseUri, Map<String,String> baseUriVars) {
+        String uri = (baseUri != null ? baseUri.toString() : "") + (suburl != null ? suburl : "");
+        Map<String,String> allvars = concat(baseUriVars, vars);
+        
+        if (allvars != null && allvars.size() > 0) {
+            uri += "?" + HttpTool.encodeUrlParams(allvars);
+        }
+        
+        return URI.create(uri);
+    }
+
+    public Map<String, String> buildHeaders(Map<String, String> baseHeaders) {
+        return MutableMap.<String,String>builder()
+                .putAll(baseHeaders)
+                .putAll(headers)
+                .build();
+    }
+    
+    @SuppressWarnings("unchecked")
+    private <K,V> Map<K,V> concat(Map<? extends K,? extends V> map1, Map<? extends K,? extends V> map2) {
+        if (map1 == null || map1.isEmpty()) return (Map<K,V>) map2;
+        if (map2 == null || map2.isEmpty()) return (Map<K,V>) map1;
+        
+        // TODO Not using Immutable builder, because that fails if duplicates in map1 and map2
+        return MutableMap.<K,V>builder().putAll(map1).putAll(map2).build();
+    }
+
+    @Override protected String toStringBaseName() { return "http"; }
+    @Override protected String toStringPollSource() { return suburl; }
+    @Override
+    protected MutableList<Object> equalsFields() {
+        return super.equalsFields().appendIfNotNull(method).appendIfNotNull(vars).appendIfNotNull(headers)
+            .appendIfNotNull(body).appendIfNotNull(connectionTimeout).appendIfNotNull(socketTimeout);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/feed/http/HttpPollValue.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/feed/http/HttpPollValue.java b/core/src/main/java/org/apache/brooklyn/feed/http/HttpPollValue.java
new file mode 100644
index 0000000..5414cc4
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/feed/http/HttpPollValue.java
@@ -0,0 +1,40 @@
+/*
+ * 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.feed.http;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.util.core.http.HttpToolResponse;
+
+/** @deprecated since 0.7.0, use {@link HttpToolResponse}.
+ * the old {@link HttpPollValue} concrete class has been renamed {@link HttpToolResponse}
+ * because it has nothing specific to polls. this is now just a transitional interface. */
+@Deprecated
+public interface HttpPollValue {
+
+    public int getResponseCode();
+    public String getReasonPhrase();
+    public long getStartTime();
+    public long getLatencyFullContent();
+    public long getLatencyFirstResponse();
+    public Map<String, List<String>> getHeaderLists();
+    public byte[] getContent();
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/feed/http/HttpPolls.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/feed/http/HttpPolls.java b/core/src/main/java/org/apache/brooklyn/feed/http/HttpPolls.java
new file mode 100644
index 0000000..10c3b3e
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/feed/http/HttpPolls.java
@@ -0,0 +1,39 @@
+/*
+ * 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.feed.http;
+
+import java.net.URI;
+
+import org.apache.brooklyn.util.core.http.HttpTool;
+import org.apache.brooklyn.util.core.http.HttpToolResponse;
+import org.apache.http.impl.client.DefaultHttpClient;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * @deprecated since 0.7; use {@link HttpTool}
+ */
+@Deprecated
+public class HttpPolls {
+
+    public static HttpToolResponse executeSimpleGet(URI uri) {
+        return HttpTool.httpGet(new DefaultHttpClient(), uri, ImmutableMap.<String,String>of());
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/feed/http/HttpValueFunctions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/feed/http/HttpValueFunctions.java b/core/src/main/java/org/apache/brooklyn/feed/http/HttpValueFunctions.java
new file mode 100644
index 0000000..75dab74
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/feed/http/HttpValueFunctions.java
@@ -0,0 +1,154 @@
+/*
+ * 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.feed.http;
+
+import java.util.List;
+
+import org.apache.brooklyn.util.core.http.HttpToolResponse;
+import org.apache.brooklyn.util.guava.Functionals;
+
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Lists;
+import com.google.gson.JsonElement;
+
+public class HttpValueFunctions {
+
+    private HttpValueFunctions() {} // instead use static utility methods
+    
+    public static Function<HttpToolResponse, Integer> responseCode() {
+        return new ResponseCode();
+    }
+    
+    /** @deprecated since 0.7.0; only here for deserialization of persisted state */
+    private static Function<HttpToolResponse, Integer> responseCodeLegacy() {
+        return new Function<HttpToolResponse, Integer>() {
+            @Override public Integer apply(HttpToolResponse input) {
+                return input.getResponseCode();
+            }
+        };
+    }
+
+    private static class ResponseCode implements Function<HttpToolResponse, Integer> {
+        @Override public Integer apply(HttpToolResponse input) {
+            return input.getResponseCode();
+        }
+    }
+
+    public static Function<HttpToolResponse, Boolean> responseCodeEquals(final int expected) {
+        return Functionals.chain(HttpValueFunctions.responseCode(), Functions.forPredicate(Predicates.equalTo(expected)));
+    }
+    
+    public static Function<HttpToolResponse, Boolean> responseCodeEquals(final int... expected) {
+        List<Integer> expectedList = Lists.newArrayList();
+        for (int e : expected) {
+            expectedList.add((Integer)e);
+        }
+        return Functionals.chain(HttpValueFunctions.responseCode(), Functions.forPredicate(Predicates.in(expectedList)));
+    }
+
+    public static Function<HttpToolResponse, String> stringContentsFunction() {
+        return new StringContents();
+    }
+    
+    /** @deprecated since 0.7.0; only here for deserialization of persisted state */
+    private static Function<HttpToolResponse, String> stringContentsFunctionLegacy() {
+        return new Function<HttpToolResponse, String>() {
+            @Override public String apply(HttpToolResponse input) {
+                return input.getContentAsString();
+            }
+        };
+    }
+
+    private static class StringContents implements Function<HttpToolResponse, String> {
+        @Override public String apply(HttpToolResponse input) {
+            return input.getContentAsString();
+        }
+    }
+
+    public static Function<HttpToolResponse, JsonElement> jsonContents() {
+        return Functionals.chain(stringContentsFunction(), JsonFunctions.asJson());
+    }
+    
+    public static <T> Function<HttpToolResponse, T> jsonContents(String element, Class<T> expected) {
+        return jsonContents(new String[] {element}, expected);
+    }
+    
+    public static <T> Function<HttpToolResponse, T> jsonContents(String[] elements, Class<T> expected) {
+        return Functionals.chain(jsonContents(), JsonFunctions.walk(elements), JsonFunctions.cast(expected));
+    }
+
+    public static <T> Function<HttpToolResponse, T> jsonContentsFromPath(String path){
+        return Functionals.chain(jsonContents(), JsonFunctions.<T>getPath(path));
+    }
+    
+    public static Function<HttpToolResponse, Long> latency() {
+        return new Latency();
+    }
+
+    /** @deprecated since 0.7.0; only here for deserialization of persisted state */
+    private static Function<HttpToolResponse, Long> latencyLegacy() {
+        return new Function<HttpToolResponse, Long>() {
+            public Long apply(HttpToolResponse input) {
+                return input.getLatencyFullContent();
+            }
+        };
+    }
+
+    private static class Latency implements Function<HttpToolResponse, Long> {
+        public Long apply(HttpToolResponse input) {
+            return input.getLatencyFullContent();
+        }
+    };
+
+    public static Function<HttpToolResponse, Boolean> containsHeader(String header) {
+        return new ContainsHeader(header);
+    }
+
+    private static class ContainsHeader implements Function<HttpToolResponse, Boolean> {
+        private final String header;
+
+        public ContainsHeader(String header) {
+            this.header = header;
+        }
+        @Override
+        public Boolean apply(HttpToolResponse input) {
+            List<String> actual = input.getHeaderLists().get(header);
+            return actual != null && actual.size() > 0;
+        }
+    }
+    
+
+    /** @deprecated since 0.7.0 use {@link Functionals#chain(Function, Function)} */ @Deprecated
+    public static <A,B,C> Function<A,C> chain(final Function<A,? extends B> f1, final Function<B,C> f2) {
+        return Functionals.chain(f1, f2);
+    }
+    
+    /** @deprecated since 0.7.0 use {@link Functionals#chain(Function, Function, Function)} */ @Deprecated
+    public static <A,B,C,D> Function<A,D> chain(final Function<A,? extends B> f1, final Function<B,? extends C> f2, final Function<C,D> f3) {
+        return Functionals.chain(f1, f2, f3);
+    }
+
+    /** @deprecated since 0.7.0 use {@link Functionals#chain(Function, Function, Function, Function)} */ @Deprecated
+    public static <A,B,C,D,E> Function<A,E> chain(final Function<A,? extends B> f1, final Function<B,? extends C> f2, final Function<C,? extends D> f3, final Function<D,E> f4) {
+        return Functionals.chain(f1, f2, f3, f4);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/feed/http/JsonFunctions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/feed/http/JsonFunctions.java b/core/src/main/java/org/apache/brooklyn/feed/http/JsonFunctions.java
new file mode 100644
index 0000000..a3e04cd
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/feed/http/JsonFunctions.java
@@ -0,0 +1,235 @@
+/*
+ * 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.feed.http;
+
+import java.lang.reflect.Array;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.util.guava.Functionals;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.guava.MaybeFunctions;
+
+import com.google.common.base.Function;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Lists;
+import com.google.gson.*;
+import com.jayway.jsonpath.JsonPath;
+
+public class JsonFunctions {
+
+    private JsonFunctions() {} // instead use static utility methods
+    
+    public static Function<String, JsonElement> asJson() {
+        return new Function<String, JsonElement>() {
+            @Override public JsonElement apply(String input) {
+                return new JsonParser().parse(input);
+            }
+        };
+    }
+
+    public static <T> Function<JsonElement, List<T>> forEach(final Function<JsonElement, T> func) {
+        return new Function<JsonElement, List<T>>() {
+            @Override public List<T> apply(JsonElement input) {
+                JsonArray array = (JsonArray) input;
+                List<T> result = Lists.newArrayList();
+                for (int i = 0; i < array.size(); i++) {
+                    result.add(func.apply(array.get(i)));
+                }
+                return result;
+            }
+        };
+    }
+
+    
+    /** as {@link #walkM(Iterable)} taking a single string consisting of a dot separated path */
+    public static Function<JsonElement, JsonElement> walk(String elementOrDotSeparatedElements) {
+        return walk( Splitter.on('.').split(elementOrDotSeparatedElements) );
+    }
+
+    /** as {@link #walkM(Iterable)} taking a series of strings (dot separators not respected here) */
+    public static Function<JsonElement, JsonElement> walk(final String... elements) {
+        return walk(Arrays.asList(elements));
+    }
+
+    /** returns a function which traverses the supplied path of entries in a json object (maps of maps of maps...), 
+     * @throws NoSuchElementException if any path is not present as a key in that map */
+    public static Function<JsonElement, JsonElement> walk(final Iterable<String> elements) {
+        // could do this instead, pointing at Maybe for this, and for walkN, but it's slightly less efficient
+//      return Functionals.chain(MaybeFunctions.<JsonElement>wrap(), walkM(elements), MaybeFunctions.<JsonElement>get());
+
+        return new Function<JsonElement, JsonElement>() {
+            @Override public JsonElement apply(JsonElement input) {
+                JsonElement curr = input;
+                for (String element : elements) {
+                    JsonObject jo = curr.getAsJsonObject();
+                    curr = jo.get(element);
+                    if (curr==null)
+                        throw new NoSuchElementException("No element '"+element+" in JSON, when walking "+elements);
+                }
+                return curr;
+            }
+        };
+    }
+
+    
+    /** as {@link #walk(String)} but if any element is not found it simply returns null */
+    public static Function<JsonElement, JsonElement> walkN(@Nullable String elements) {
+        return walkN( Splitter.on('.').split(elements) );
+    }
+
+    /** as {@link #walk(String...))} but if any element is not found it simply returns null */
+    public static Function<JsonElement, JsonElement> walkN(final String... elements) {
+        return walkN(Arrays.asList(elements));
+    }
+
+    /** as {@link #walk(Iterable))} but if any element is not found it simply returns null */
+    public static Function<JsonElement, JsonElement> walkN(final Iterable<String> elements) {
+        return new Function<JsonElement, JsonElement>() {
+            @Override public JsonElement apply(JsonElement input) {
+                JsonElement curr = input;
+                for (String element : elements) {
+                    if (curr==null) return null;
+                    JsonObject jo = curr.getAsJsonObject();
+                    curr = jo.get(element);
+                }
+                return curr;
+            }
+        };
+    }
+
+    /** as {@link #walk(String))} and {@link #walk(Iterable)} */
+    public static Function<Maybe<JsonElement>, Maybe<JsonElement>> walkM(@Nullable String elements) {
+        return walkM( Splitter.on('.').split(elements) );
+    }
+
+    /** as {@link #walk(String...))} and {@link #walk(Iterable)} */
+    public static Function<Maybe<JsonElement>, Maybe<JsonElement>> walkM(final String... elements) {
+        return walkM(Arrays.asList(elements));
+    }
+
+    /** as {@link #walk(Iterable))} but working with objects which {@link Maybe} contain {@link JsonElement},
+     * simply preserving a {@link Maybe#absent()} object if additional walks are requested upon it
+     * (cf jquery) */
+    public static Function<Maybe<JsonElement>, Maybe<JsonElement>> walkM(final Iterable<String> elements) {
+        return new Function<Maybe<JsonElement>, Maybe<JsonElement>>() {
+            @Override public Maybe<JsonElement> apply(Maybe<JsonElement> input) {
+                Maybe<JsonElement> curr = input;
+                for (String element : elements) {
+                    if (curr.isAbsent()) return curr;
+                    JsonObject jo = curr.get().getAsJsonObject();
+                    JsonElement currO = jo.get(element);
+                    if (currO==null) return Maybe.absent("No element '"+element+" in JSON, when walking "+elements);
+                    curr = Maybe.of(currO);
+                }
+                return curr;
+            }
+        };
+    }
+
+    /**
+     * returns an element from a single json primitive value given a full path {@link com.jayway.jsonpath.JsonPath}
+     */
+    public static <T> Function<JsonElement,T> getPath(final String path) {
+        return new Function<JsonElement, T>() {
+            @SuppressWarnings("unchecked")
+            @Override public T apply(JsonElement input) {
+                String jsonString = input.toString();
+                Object rawElement = JsonPath.read(jsonString, path);
+                return (T) rawElement;
+            }
+        };
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> Function<JsonElement, T> cast(final Class<T> expected) {
+        return new Function<JsonElement, T>() {
+            @Override public T apply(JsonElement input) {
+                if (input == null) {
+                    return (T) null;
+                } else if (input.isJsonNull()) {
+                    return (T) null;
+                } else if (expected == boolean.class || expected == Boolean.class) {
+                    return (T) (Boolean) input.getAsBoolean();
+                } else if (expected == char.class || expected == Character.class) {
+                    return (T) (Character) input.getAsCharacter();
+                } else if (expected == byte.class || expected == Byte.class) {
+                    return (T) (Byte) input.getAsByte();
+                } else if (expected == short.class || expected == Short.class) {
+                    return (T) (Short) input.getAsShort();
+                } else if (expected == int.class || expected == Integer.class) {
+                    return (T) (Integer) input.getAsInt();
+                } else if (expected == long.class || expected == Long.class) {
+                    return (T) (Long) input.getAsLong();
+                } else if (expected == float.class || expected == Float.class) {
+                    return (T) (Float) input.getAsFloat();
+                } else if (expected == double.class || expected == Double.class) {
+                    return (T) (Double) input.getAsDouble();
+                } else if (expected == BigDecimal.class) {
+                    return (T) input.getAsBigDecimal();
+                } else if (expected == BigInteger.class) {
+                    return (T) input.getAsBigInteger();
+                } else if (Number.class.isAssignableFrom(expected)) {
+                    // TODO Will result in a class-cast if it's an unexpected sub-type of Number not handled above
+                    return (T) input.getAsNumber();
+                } else if (expected == String.class) {
+                    return (T) input.getAsString();
+                } else if (expected.isArray()) {
+                    JsonArray array = input.getAsJsonArray();
+                    Class<?> componentType = expected.getComponentType();
+                    if (JsonElement.class.isAssignableFrom(componentType)) {
+                        JsonElement[] result = new JsonElement[array.size()];
+                        for (int i = 0; i < array.size(); i++) {
+                            result[i] = array.get(i);
+                        }
+                        return (T) result;
+                    } else {
+                        Object[] result = (Object[]) Array.newInstance(componentType, array.size());
+                        for (int i = 0; i < array.size(); i++) {
+                            result[i] = cast(componentType).apply(array.get(i));
+                        }
+                        return (T) result;
+                    }
+                } else {
+                    throw new IllegalArgumentException("Cannot cast json element to type "+expected);
+                }
+            }
+        };
+    }
+    
+    public static <T> Function<Maybe<JsonElement>, T> castM(final Class<T> expected) {
+        return Functionals.chain(MaybeFunctions.<JsonElement>get(), cast(expected));
+    }
+    
+    public static <T> Function<Maybe<JsonElement>, T> castM(final Class<T> expected, final T defaultValue) {
+        return new Function<Maybe<JsonElement>, T>() {
+            @Override
+            public T apply(Maybe<JsonElement> input) {
+                if (input.isAbsent()) return defaultValue;
+                return cast(expected).apply(input.get());
+            }
+        };
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/feed/shell/ShellFeed.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/feed/shell/ShellFeed.java b/core/src/main/java/org/apache/brooklyn/feed/shell/ShellFeed.java
new file mode 100644
index 0000000..caeb21a
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/feed/shell/ShellFeed.java
@@ -0,0 +1,273 @@
+/*
+ * 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.feed.shell;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.mgmt.ExecutionContext;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.feed.AbstractFeed;
+import org.apache.brooklyn.core.feed.AttributePollHandler;
+import org.apache.brooklyn.core.feed.DelegatingPollHandler;
+import org.apache.brooklyn.core.feed.Poller;
+import org.apache.brooklyn.feed.function.FunctionFeed;
+import org.apache.brooklyn.feed.ssh.SshFeed;
+import org.apache.brooklyn.feed.ssh.SshPollValue;
+import org.apache.brooklyn.util.core.task.system.ProcessTaskFactory;
+import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.util.core.task.system.internal.SystemProcessTaskFactory.ConcreteSystemProcessTaskFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Optional;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
+import com.google.common.reflect.TypeToken;
+
+/**
+ * Provides a feed of attribute values, by executing shell commands (on the local machine where 
+ * this instance of brooklyn is running). Useful e.g. for paas tools such as Cloud Foundry vmc 
+ * which operate against a remote target.
+ * 
+ * Example usage (e.g. in an entity that extends SoftwareProcessImpl):
+ * <pre>
+ * {@code
+ * private ShellFeed feed;
+ * 
+ * //@Override
+ * protected void connectSensors() {
+ *   super.connectSensors();
+ *   
+ *   feed = ShellFeed.builder()
+ *       .entity(this)
+ *       .machine(mySshMachineLachine)
+ *       .poll(new ShellPollConfig<Long>(DISK_USAGE)
+ *           .command("df -P | grep /dev")
+ *           .failOnNonZeroResultCode(true)
+ *           .onSuccess(new Function<SshPollValue, Long>() {
+ *                public Long apply(SshPollValue input) {
+ *                  String[] parts = input.getStdout().split("[ \\t]+");
+ *                  return Long.parseLong(parts[2]);
+ *                }}))
+ *       .build();
+ * }
+ * 
+ * {@literal @}Override
+ * protected void disconnectSensors() {
+ *   super.disconnectSensors();
+ *   if (feed != null) feed.stop();
+ * }
+ * }
+ * </pre>
+ * 
+ * @see SshFeed (to run on remote machines)
+ * @see FunctionFeed (for arbitrary functions)
+ * 
+ * @author aled
+ */
+public class ShellFeed extends AbstractFeed {
+
+    public static final Logger log = LoggerFactory.getLogger(ShellFeed.class);
+
+    @SuppressWarnings("serial")
+    private static final ConfigKey<SetMultimap<ShellPollIdentifier, ShellPollConfig<?>>> POLLS = ConfigKeys.newConfigKey(
+            new TypeToken<SetMultimap<ShellPollIdentifier, ShellPollConfig<?>>>() {},
+            "polls");
+
+    public static Builder builder() {
+        return new Builder();
+    }
+    
+    public static class Builder {
+        private EntityLocal entity;
+        private long period = 500;
+        private TimeUnit periodUnits = TimeUnit.MILLISECONDS;
+        private List<ShellPollConfig<?>> polls = Lists.newArrayList();
+        private String uniqueTag;
+        private volatile boolean built;
+        
+        public Builder entity(EntityLocal val) {
+            this.entity = val;
+            return this;
+        }
+        public Builder period(long millis) {
+            return period(millis, TimeUnit.MILLISECONDS);
+        }
+        public Builder period(long val, TimeUnit units) {
+            this.period = val;
+            this.periodUnits = units;
+            return this;
+        }
+        public Builder poll(ShellPollConfig<?> config) {
+            polls.add(config);
+            return this;
+        }
+        public Builder uniqueTag(String uniqueTag) {
+            this.uniqueTag = uniqueTag;
+            return this;
+        }
+        public ShellFeed build() {
+            built = true;
+            ShellFeed result = new ShellFeed(this);
+            result.setEntity(checkNotNull(entity, "entity"));
+            result.start();
+            return result;
+        }
+        @Override
+        protected void finalize() {
+            if (!built) log.warn("ShellFeed.Builder created, but build() never called");
+        }
+    }
+    
+    private static class ShellPollIdentifier {
+        final String command;
+        final Map<String, String> env;
+        final File dir;
+        final String input;
+        final String context;
+        final long timeout;
+
+        private ShellPollIdentifier(String command, Map<String, String> env, File dir, String input, String context, long timeout) {
+            this.command = checkNotNull(command, "command");
+            this.env = checkNotNull(env, "env");
+            this.dir = dir;
+            this.input = input;
+            this.context = checkNotNull(context, "context");
+            this.timeout = timeout;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(command, env, dir, input, timeout);
+        }
+        
+        @Override
+        public boolean equals(Object other) {
+            if (!(other instanceof ShellPollIdentifier)) {
+                return false;
+            }
+            ShellPollIdentifier o = (ShellPollIdentifier) other;
+            return Objects.equal(command, o.command) &&
+                    Objects.equal(env, o.env) &&
+                    Objects.equal(dir, o.dir) &&
+                    Objects.equal(input, o.input) &&
+                    Objects.equal(timeout, o.timeout);
+        }
+    }
+    
+    /**
+     * For rebind; do not call directly; use builder
+     */
+    public ShellFeed() {
+    }
+
+    protected ShellFeed(Builder builder) {
+        super();
+
+        SetMultimap<ShellPollIdentifier, ShellPollConfig<?>> polls = HashMultimap.<ShellPollIdentifier,ShellPollConfig<?>>create();
+        for (ShellPollConfig<?> config : builder.polls) {
+            if (!config.isEnabled()) continue;
+            @SuppressWarnings({ "unchecked", "rawtypes" })
+            ShellPollConfig<?> configCopy = new ShellPollConfig(config);
+            if (configCopy.getPeriod() < 0) configCopy.period(builder.period, builder.periodUnits);
+            String command = config.getCommand();
+            Map<String, String> env = config.getEnv();
+            File dir = config.getDir();
+            String input = config.getInput();
+            String context = config.getSensor().getName();
+            long timeout = config.getTimeout();
+
+            polls.put(new ShellPollIdentifier(command, env, dir, input, context, timeout), configCopy);
+        }
+        setConfig(POLLS, polls);
+        initUniqueTag(builder.uniqueTag, polls.values());
+    }
+
+    @Override
+    protected void preStart() {
+        SetMultimap<ShellPollIdentifier, ShellPollConfig<?>> polls = getConfig(POLLS);
+        
+        for (final ShellPollIdentifier pollInfo : polls.keySet()) {
+            Set<ShellPollConfig<?>> configs = polls.get(pollInfo);
+            long minPeriod = Integer.MAX_VALUE;
+            Set<AttributePollHandler<? super SshPollValue>> handlers = Sets.newLinkedHashSet();
+
+            for (ShellPollConfig<?> config : configs) {
+                handlers.add(new AttributePollHandler<SshPollValue>(config, entity, this));
+                if (config.getPeriod() > 0) minPeriod = Math.min(minPeriod, config.getPeriod());
+            }
+
+            final ProcessTaskFactory<?> taskFactory = newTaskFactory(pollInfo.command, pollInfo.env, pollInfo.dir, 
+                    pollInfo.input, pollInfo.context, pollInfo.timeout);
+            final ExecutionContext executionContext = ((EntityInternal) entity).getManagementSupport().getExecutionContext();
+
+            getPoller().scheduleAtFixedRate(
+                    new Callable<SshPollValue>() {
+                        @Override public SshPollValue call() throws Exception {
+                            ProcessTaskWrapper<?> taskWrapper = taskFactory.newTask();
+                            executionContext.submit(taskWrapper);
+                            taskWrapper.block();
+                            Optional<Integer> exitCode = Optional.fromNullable(taskWrapper.getExitCode());
+                            return new SshPollValue(null, exitCode.or(-1), taskWrapper.getStdout(), taskWrapper.getStderr());
+                        }}, 
+                    new DelegatingPollHandler<SshPollValue>(handlers), 
+                    minPeriod);
+        }
+    }
+    
+    @SuppressWarnings("unchecked")
+    protected Poller<SshPollValue> getPoller() {
+        return (Poller<SshPollValue>) super.getPoller();
+    }
+    
+    /**
+     * Executes the given command (using `bash -l -c $command`, so as to have a good path set).
+     * 
+     * @param command The command to execute
+     * @param env     Environment variable settings, in format name=value
+     * @param dir     Working directory, or null to inherit from current process
+     * @param input   Input to send to the command (if not null)
+     */
+    protected ProcessTaskFactory<?> newTaskFactory(final String command, Map<String,String> env, File dir, String input, final String summary, final long timeout) {
+        // FIXME Add generic timeout() support to task ExecutionManager
+        if (timeout > 0) {
+            log.warn("Timeout ({}ms) not currently supported for ShellFeed {}", timeout, this);
+        }
+
+        return new ConcreteSystemProcessTaskFactory<Object>(command)
+                .environmentVariables(env)
+                .loginShell(true)
+                .directory(dir)
+                .runAsCommand()
+                .summary(summary);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/feed/shell/ShellPollConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/feed/shell/ShellPollConfig.java b/core/src/main/java/org/apache/brooklyn/feed/shell/ShellPollConfig.java
new file mode 100644
index 0000000..e1147c3
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/feed/shell/ShellPollConfig.java
@@ -0,0 +1,125 @@
+/*
+ * 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.feed.shell;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.File;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.feed.PollConfig;
+import org.apache.brooklyn.feed.ssh.SshPollValue;
+import org.apache.brooklyn.util.collections.MutableList;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Maps;
+
+public class ShellPollConfig<T> extends PollConfig<SshPollValue, T, ShellPollConfig<T>> {
+
+    private String command;
+    private Map<String,String> env = Maps.newLinkedHashMap();
+    private long timeout = -1;
+    private File dir;
+    private String input;
+
+    public static final Predicate<SshPollValue> DEFAULT_SUCCESS = new Predicate<SshPollValue>() {
+        @Override
+        public boolean apply(@Nullable SshPollValue input) {
+            return input != null && input.getExitStatus() == 0;
+        }};
+
+    public ShellPollConfig(AttributeSensor<T> sensor) {
+        super(sensor);
+        super.checkSuccess(DEFAULT_SUCCESS);
+    }
+
+    public ShellPollConfig(ShellPollConfig<T> other) {
+        super(other);
+        command = other.command;
+        env = other.env;
+        timeout = other.timeout;
+        dir = other.dir;
+        input = other.input;
+    }
+    
+    public String getCommand() {
+        return command;
+    }
+    
+    public Map<String, String> getEnv() {
+        return env;
+    }
+
+    public File getDir() {
+        return dir;
+    }
+
+    public String getInput() {
+        return input;
+    }
+    
+    public long getTimeout() {
+        return timeout;
+    }
+    
+    public ShellPollConfig<T> command(String val) {
+        this.command = val;
+        return this;
+    }
+
+    public ShellPollConfig<T> env(String key, String val) {
+        env.put(checkNotNull(key, "key"), checkNotNull(val, "val"));
+        return this;
+    }
+    
+    public ShellPollConfig<T> env(Map<String,String> val) {
+        for (Map.Entry<String, String> entry : checkNotNull(val, "map").entrySet()) {
+            env(entry.getKey(), entry.getValue());
+        }
+        return this;
+    }
+    
+    public ShellPollConfig<T> dir(File val) {
+        this.dir = val;
+        return this;
+    }
+    
+    public ShellPollConfig<T> input(String val) {
+        this.input = val;
+        return this;
+    }
+    
+    public ShellPollConfig<T> timeout(long timeout) {
+        return timeout(timeout, TimeUnit.MILLISECONDS);
+    }
+    
+    public ShellPollConfig<T> timeout(long timeout, TimeUnit units) {
+        this.timeout = units.toMillis(timeout);
+        return this;
+    }
+
+    @Override protected String toStringBaseName() { return "shell"; }
+    @Override protected String toStringPollSource() { return command; }
+    @Override protected MutableList<Object> equalsFields() { return super.equalsFields().appendIfNotNull(command); }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/feed/ssh/SshFeed.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/feed/ssh/SshFeed.java b/core/src/main/java/org/apache/brooklyn/feed/ssh/SshFeed.java
new file mode 100644
index 0000000..8663137
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/feed/ssh/SshFeed.java
@@ -0,0 +1,290 @@
+/*
+ * 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.feed.ssh;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.feed.AbstractFeed;
+import org.apache.brooklyn.core.feed.AttributePollHandler;
+import org.apache.brooklyn.core.feed.DelegatingPollHandler;
+import org.apache.brooklyn.core.feed.Poller;
+import org.apache.brooklyn.core.location.Locations;
+import org.apache.brooklyn.core.location.Machines;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.core.internal.ssh.SshTool;
+import org.apache.brooklyn.util.time.Duration;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
+import com.google.common.reflect.TypeToken;
+
+/**
+ * Provides a feed of attribute values, by polling over ssh.
+ * 
+ * Example usage (e.g. in an entity that extends SoftwareProcessImpl):
+ * <pre>
+ * {@code
+ * private SshFeed feed;
+ * 
+ * //@Override
+ * protected void connectSensors() {
+ *   super.connectSensors();
+ *   
+ *   feed = SshFeed.builder()
+ *       .entity(this)
+ *       .machine(mySshMachineLachine)
+ *       .poll(new SshPollConfig<Boolean>(SERVICE_UP)
+ *           .command("rabbitmqctl -q status")
+ *           .onSuccess(new Function<SshPollValue, Boolean>() {
+ *               public Boolean apply(SshPollValue input) {
+ *                 return (input.getExitStatus() == 0);
+ *               }}))
+ *       .build();
+ * }
+ * 
+ * {@literal @}Override
+ * protected void disconnectSensors() {
+ *   super.disconnectSensors();
+ *   if (feed != null) feed.stop();
+ * }
+ * }
+ * </pre>
+ * 
+ * @author aled
+ */
+public class SshFeed extends AbstractFeed {
+
+    public static final Logger log = LoggerFactory.getLogger(SshFeed.class);
+    
+    @SuppressWarnings("serial")
+    public static final ConfigKey<Supplier<SshMachineLocation>> MACHINE = ConfigKeys.newConfigKey(
+            new TypeToken<Supplier<SshMachineLocation>>() {},
+            "machine");
+    
+    public static final ConfigKey<Boolean> EXEC_AS_COMMAND = ConfigKeys.newBooleanConfigKey("execAsCommand");
+    
+    @SuppressWarnings("serial")
+    public static final ConfigKey<SetMultimap<SshPollIdentifier, SshPollConfig<?>>> POLLS = ConfigKeys.newConfigKey(
+            new TypeToken<SetMultimap<SshPollIdentifier, SshPollConfig<?>>>() {},
+            "polls");
+    
+    public static Builder builder() {
+        return new Builder();
+    }
+    
+    public static class Builder {
+        private EntityLocal entity;
+        private boolean onlyIfServiceUp = false;
+        private Supplier<SshMachineLocation> machine;
+        private Duration period = Duration.of(500, TimeUnit.MILLISECONDS);
+        private List<SshPollConfig<?>> polls = Lists.newArrayList();
+        private boolean execAsCommand = false;
+        private String uniqueTag;
+        private volatile boolean built;
+        
+        public Builder entity(EntityLocal val) {
+            this.entity = val;
+            return this;
+        }
+        public Builder onlyIfServiceUp() { return onlyIfServiceUp(true); }
+        public Builder onlyIfServiceUp(boolean onlyIfServiceUp) { 
+            this.onlyIfServiceUp = onlyIfServiceUp; 
+            return this; 
+        }
+        /** optional, to force a machine; otherwise it is inferred from the entity */
+        public Builder machine(SshMachineLocation val) { return machine(Suppliers.ofInstance(val)); }
+        /** optional, to force a machine; otherwise it is inferred from the entity */
+        public Builder machine(Supplier<SshMachineLocation> val) {
+            this.machine = val;
+            return this;
+        }
+        public Builder period(Duration period) {
+            this.period = period;
+            return this;
+        }
+        public Builder period(long millis) {
+            return period(Duration.of(millis, TimeUnit.MILLISECONDS));
+        }
+        public Builder period(long val, TimeUnit units) {
+            return period(Duration.of(val, units));
+        }
+        public Builder poll(SshPollConfig<?> config) {
+            polls.add(config);
+            return this;
+        }
+        public Builder execAsCommand() {
+            execAsCommand = true;
+            return this;
+        }
+        public Builder execAsScript() {
+            execAsCommand = false;
+            return this;
+        }
+        public Builder uniqueTag(String uniqueTag) {
+            this.uniqueTag = uniqueTag;
+            return this;
+        }
+        public SshFeed build() {
+            built = true;
+            SshFeed result = new SshFeed(this);
+            result.setEntity(checkNotNull(entity, "entity"));
+            result.start();
+            return result;
+        }
+        @Override
+        protected void finalize() {
+            if (!built) log.warn("SshFeed.Builder created, but build() never called");
+        }
+    }
+    
+    private static class SshPollIdentifier {
+        final Supplier<String> command;
+        final Supplier<Map<String, String>> env;
+
+        private SshPollIdentifier(Supplier<String> command, Supplier<Map<String, String>> env) {
+            this.command = checkNotNull(command, "command");
+            this.env = checkNotNull(env, "env");
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(command, env);
+        }
+        
+        @Override
+        public boolean equals(Object other) {
+            if (!(other instanceof SshPollIdentifier)) {
+                return false;
+            }
+            SshPollIdentifier o = (SshPollIdentifier) other;
+            return Objects.equal(command, o.command) &&
+                    Objects.equal(env, o.env);
+        }
+    }
+    
+    /** @deprecated since 0.7.0, use static convenience on {@link Locations} */
+    @Deprecated
+    public static SshMachineLocation getMachineOfEntity(Entity entity) {
+        return Machines.findUniqueSshMachineLocation(entity.getLocations()).orNull();
+    }
+
+    /**
+     * For rebind; do not call directly; use builder
+     */
+    public SshFeed() {
+    }
+    
+    protected SshFeed(final Builder builder) {
+        setConfig(ONLY_IF_SERVICE_UP, builder.onlyIfServiceUp);
+        setConfig(MACHINE, builder.machine != null ? builder.machine : null);
+        setConfig(EXEC_AS_COMMAND, builder.execAsCommand);
+        
+        SetMultimap<SshPollIdentifier, SshPollConfig<?>> polls = HashMultimap.<SshPollIdentifier,SshPollConfig<?>>create();
+        for (SshPollConfig<?> config : builder.polls) {
+            @SuppressWarnings({ "unchecked", "rawtypes" })
+            SshPollConfig<?> configCopy = new SshPollConfig(config);
+            if (configCopy.getPeriod() < 0) configCopy.period(builder.period);
+            polls.put(new SshPollIdentifier(config.getCommandSupplier(), config.getEnvSupplier()), configCopy);
+        }
+        setConfig(POLLS, polls);
+        initUniqueTag(builder.uniqueTag, polls.values());
+    }
+
+    protected SshMachineLocation getMachine() {
+        Supplier<SshMachineLocation> supplier = getConfig(MACHINE);
+        if (supplier != null) {
+            return supplier.get();
+        } else {
+            return Locations.findUniqueSshMachineLocation(entity.getLocations()).get();
+        }
+    }
+    
+    @Override
+    protected void preStart() {
+        SetMultimap<SshPollIdentifier, SshPollConfig<?>> polls = getConfig(POLLS);
+        
+        for (final SshPollIdentifier pollInfo : polls.keySet()) {
+            Set<SshPollConfig<?>> configs = polls.get(pollInfo);
+            long minPeriod = Integer.MAX_VALUE;
+            Set<AttributePollHandler<? super SshPollValue>> handlers = Sets.newLinkedHashSet();
+
+            for (SshPollConfig<?> config : configs) {
+                handlers.add(new AttributePollHandler<SshPollValue>(config, entity, this));
+                if (config.getPeriod() > 0) minPeriod = Math.min(minPeriod, config.getPeriod());
+            }
+            
+            getPoller().scheduleAtFixedRate(
+                    new Callable<SshPollValue>() {
+                        public SshPollValue call() throws Exception {
+                            return exec(pollInfo.command.get(), pollInfo.env.get());
+                        }}, 
+                    new DelegatingPollHandler<SshPollValue>(handlers),
+                    minPeriod);
+        }
+    }
+    
+    @SuppressWarnings("unchecked")
+    protected Poller<SshPollValue> getPoller() {
+        return (Poller<SshPollValue>) super.getPoller();
+    }
+    
+    private SshPollValue exec(String command, Map<String,String> env) throws IOException {
+        SshMachineLocation machine = getMachine();
+        Boolean execAsCommand = getConfig(EXEC_AS_COMMAND);
+        if (log.isTraceEnabled()) log.trace("Ssh polling for {}, executing {} with env {}", new Object[] {machine, command, env});
+        ByteArrayOutputStream stdout = new ByteArrayOutputStream();
+        ByteArrayOutputStream stderr = new ByteArrayOutputStream();
+
+        int exitStatus;
+        ConfigBag flags = ConfigBag.newInstance()
+            .configure(SshTool.PROP_NO_EXTRA_OUTPUT, true)
+            .configure(SshTool.PROP_OUT_STREAM, stdout)
+            .configure(SshTool.PROP_ERR_STREAM, stderr);
+        if (Boolean.TRUE.equals(execAsCommand)) {
+            exitStatus = machine.execCommands(flags.getAllConfig(),
+                    "ssh-feed", ImmutableList.of(command), env);
+        } else {
+            exitStatus = machine.execScript(flags.getAllConfig(),
+                    "ssh-feed", ImmutableList.of(command), env);
+        }
+
+        return new SshPollValue(machine, exitStatus, new String(stdout.toByteArray()), new String(stderr.toByteArray()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/feed/ssh/SshPollConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/feed/ssh/SshPollConfig.java b/core/src/main/java/org/apache/brooklyn/feed/ssh/SshPollConfig.java
new file mode 100644
index 0000000..8fec87f
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/feed/ssh/SshPollConfig.java
@@ -0,0 +1,142 @@
+/*
+ * 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.feed.ssh;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.feed.PollConfig;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.collections.MutableMap;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+
+public class SshPollConfig<T> extends PollConfig<SshPollValue, T, SshPollConfig<T>> {
+
+    private Supplier<String> commandSupplier;
+    private List<Supplier<Map<String,String>>> dynamicEnvironmentSupplier = MutableList.of();
+
+    public static final Predicate<SshPollValue> DEFAULT_SUCCESS = new Predicate<SshPollValue>() {
+        @Override
+        public boolean apply(@Nullable SshPollValue input) {
+            return input != null && input.getExitStatus() == 0;
+        }};
+
+    public SshPollConfig(AttributeSensor<T> sensor) {
+        super(sensor);
+        super.checkSuccess(DEFAULT_SUCCESS);
+    }
+
+    public SshPollConfig(SshPollConfig<T> other) {
+        super(other);
+        commandSupplier = other.commandSupplier;
+    }
+    
+    /** @deprecated since 0.7.0; use {@link #getCommandSupplier()} and resolve just-in-time */
+    public String getCommand() {
+        return getCommandSupplier().get();
+    }
+    public Supplier<String> getCommandSupplier() {
+        return commandSupplier;
+    }
+    
+    /** @deprecated since 0.7.0; use {@link #getEnvSupplier()} and resolve just-in-time */
+    public Map<String, String> getEnv() {
+        return getEnvSupplier().get();
+    }
+    public Supplier<Map<String,String>> getEnvSupplier() {
+        return new Supplier<Map<String,String>>() {
+            @Override
+            public Map<String, String> get() {
+                Map<String,String> result = MutableMap.of();
+                for (Supplier<Map<String, String>> envS: dynamicEnvironmentSupplier) {
+                    if (envS!=null) {
+                        Map<String, String> envM = envS.get();
+                        if (envM!=null) {
+                            mergeEnvMaps(envM, result);
+                        }
+                    }
+                }
+                return result;
+            }
+        };
+    }
+    
+    protected void mergeEnvMaps(Map<String,String> supplied, Map<String,String> target) {
+        if (supplied==null) return;
+        // as the value is a string there is no need to look at deep merge behaviour
+        target.putAll(supplied);
+    }
+
+    public SshPollConfig<T> command(String val) { return command(Suppliers.ofInstance(val)); }
+    public SshPollConfig<T> command(Supplier<String> val) {
+        this.commandSupplier = val;
+        return this;
+    }
+
+    /** add the given env param; sequence is as per {@link #env(Supplier)} */
+    public SshPollConfig<T> env(String key, String val) {
+        return env(Collections.singletonMap(key, val));
+    }
+    
+    /** add the given env params; sequence is as per {@link #env(Supplier)}.
+     * behaviour is undefined if the map supplied here is subsequently changed.
+     * <p>
+     * if a map's contents might change, use {@link #env(Supplier)} */
+    public SshPollConfig<T> env(Map<String,String> val) {
+        if (val==null) return this;
+        return env(Suppliers.ofInstance(val));
+    }
+
+    /** 
+     * adds the given dynamic supplier of environment variables.
+     * <p>
+     * use of a supplier allows env vars to be computed on each execution,
+     * for example to take the most recent sensor values.
+     * <p>
+     * in the case of multiple map suppliers, static maps, or static {@link #env(String, String)} 
+     * key value pairs, the order in which they are specified here is the order
+     * in which they are computed and applied. 
+     **/
+    public SshPollConfig<T> env(Supplier<Map<String,String>> val) {
+        Preconditions.checkNotNull(val);
+        dynamicEnvironmentSupplier.add(val);
+        return this;
+    }
+
+    @Override protected String toStringBaseName() { return "ssh"; }
+    @Override protected Object toStringPollSource() {
+        if (getCommandSupplier()==null) return null;
+        String command = getCommandSupplier().get();
+        return command;
+    }
+    @Override protected MutableList<Object> equalsFields() { 
+        return super.equalsFields()
+            .appendIfNotNull(getCommandSupplier()!=null ? getCommandSupplier().get() : null)
+            .appendIfNotNull(getEnvSupplier()!=null ? getEnvSupplier().get() : null); 
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/feed/ssh/SshPollValue.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/feed/ssh/SshPollValue.java b/core/src/main/java/org/apache/brooklyn/feed/ssh/SshPollValue.java
new file mode 100644
index 0000000..af0a8a6
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/feed/ssh/SshPollValue.java
@@ -0,0 +1,60 @@
+/*
+ * 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.feed.ssh;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+
+public class SshPollValue {
+
+    private final SshMachineLocation machine;
+    private final int exitStatus;
+    private final String stdout;
+    private final String stderr;
+
+    public SshPollValue(SshMachineLocation machine, int exitStatus, String stdout, String stderr) {
+        this.machine = machine;
+        this.exitStatus = exitStatus;
+        this.stdout = stdout;
+        this.stderr = stderr;
+    }
+    
+    /** The machine the command will run on. */
+    public SshMachineLocation getMachine() {
+        return machine;
+    }
+
+    /** Command exit status, or -1 if error is set. */
+    public int getExitStatus() {
+        return exitStatus;
+    }
+
+    /** Command standard output; may be null if no content available. */
+    @Nullable
+    public String getStdout() {
+        return stdout;
+    }
+
+    /** Command standard error; may be null if no content available. */
+    @Nullable
+    public String getStderr() {
+        return stderr;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/feed/ssh/SshValueFunctions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/feed/ssh/SshValueFunctions.java b/core/src/main/java/org/apache/brooklyn/feed/ssh/SshValueFunctions.java
new file mode 100644
index 0000000..370c3ce
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/feed/ssh/SshValueFunctions.java
@@ -0,0 +1,73 @@
+/*
+ * 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.feed.ssh;
+
+import javax.annotation.Nullable;
+
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.base.Predicates;
+
+public class SshValueFunctions {
+
+    public static Function<SshPollValue, Integer> exitStatus() {
+        return new Function<SshPollValue, Integer>() {
+            @Override public Integer apply(SshPollValue input) {
+                return input.getExitStatus();
+            }
+        };
+    }
+
+    public static Function<SshPollValue, String> stdout() {
+        return new Function<SshPollValue, String>() {
+            @Override public String apply(SshPollValue input) {
+                return input.getStdout();
+            }
+        };
+    }
+    
+    public static Function<SshPollValue, String> stderr() {
+        return new Function<SshPollValue, String>() {
+            @Override public String apply(SshPollValue input) {
+                return input.getStderr();
+            }
+        };
+    }
+    
+    public static Function<SshPollValue, Boolean> exitStatusEquals(final int expected) {
+        return chain(SshValueFunctions.exitStatus(), Functions.forPredicate(Predicates.equalTo(expected)));
+    }
+
+    // TODO Do we want these chain methods? Does guava have them already? Duplicated in HttpValueFunctions.
+    public static <A,B,C> Function<A,C> chain(final Function<A,? extends B> f1, final Function<B,C> f2) {
+        return new Function<A,C>() {
+            @Override public C apply(@Nullable A input) {
+                return f2.apply(f1.apply(input));
+            }
+        };
+    }
+    
+    public static <A,B,C,D> Function<A,D> chain(final Function<A,? extends B> f1, final Function<B,? extends C> f2, final Function<C,D> f3) {
+        return new Function<A,D>() {
+            @Override public D apply(@Nullable A input) {
+                return f3.apply(f2.apply(f1.apply(input)));
+            }
+        };
+    }
+}


[18/36] incubator-brooklyn git commit: Rename o.a.b.sensor.feed to o.a.b.feed and o.a.b.core.feed

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/test/java/org/apache/brooklyn/feed/jmx/JmxFeedTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/feed/jmx/JmxFeedTest.java b/software/base/src/test/java/org/apache/brooklyn/feed/jmx/JmxFeedTest.java
new file mode 100644
index 0000000..3975e68
--- /dev/null
+++ b/software/base/src/test/java/org/apache/brooklyn/feed/jmx/JmxFeedTest.java
@@ -0,0 +1,422 @@
+/*
+ * 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.feed.jmx;
+
+import static org.apache.brooklyn.test.TestUtils.executeUntilSucceeds;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.StandardEmitterMBean;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.TabularDataSupport;
+import javax.management.openmbean.TabularType;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.SensorEvent;
+import org.apache.brooklyn.api.sensor.SensorEventListener;
+import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.feed.ConfigToAttributes;
+import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.location.SimulatedLocation;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.core.test.entity.TestApplicationImpl;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.core.test.entity.TestEntityImpl;
+import org.apache.brooklyn.entity.java.JmxSupport;
+import org.apache.brooklyn.entity.java.UsesJmx;
+import org.apache.brooklyn.entity.java.UsesJmx.JmxAgentModes;
+import org.apache.brooklyn.entity.software.base.test.jmx.GeneralisedDynamicMBean;
+import org.apache.brooklyn.entity.software.base.test.jmx.JmxService;
+import org.apache.brooklyn.feed.jmx.JmxAttributePollConfig;
+import org.apache.brooklyn.feed.jmx.JmxFeed;
+import org.apache.brooklyn.feed.jmx.JmxHelper;
+import org.apache.brooklyn.feed.jmx.JmxNotificationFilters;
+import org.apache.brooklyn.feed.jmx.JmxNotificationSubscriptionConfig;
+import org.apache.brooklyn.feed.jmx.JmxOperationPollConfig;
+import org.apache.brooklyn.feed.jmx.JmxValueFunctions;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.test.TestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.testng.collections.Lists;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Test the operation of the {@link JmxFeed} class.
+ * <p>
+ * Also confirm some of the JMX setup done by {@link JmxSupport} and {@link JmxHelper},
+ * based on ports in {@link UsesJmx}.
+ * <p>
+ * TODO tests of other JMX_AGENT_MODE are done in ActiveMqIntegrationTest; 
+ * would be nice to promote some to live here
+ */
+public class JmxFeedTest {
+    
+    // FIXME Move out the JmxHelper tests into the JmxHelperTest class
+    
+    // FIXME Also test that setting poll period takes effect
+    
+    private static final Logger log = LoggerFactory.getLogger(JmxFeedTest.class);
+
+    private static final int TIMEOUT_MS = 5000;
+    private static final int SHORT_WAIT_MS = 250;
+    
+    private JmxService jmxService;
+    private TestApplication app;
+    private TestEntity entity;
+    private JmxFeed feed;
+    private JmxHelper jmxHelper;
+    
+    private AttributeSensor<Integer> intAttribute = Sensors.newIntegerSensor("brooklyn.test.intAttribute", "Brooklyn testing int attribute");
+    private AttributeSensor<String> stringAttribute = Sensors.newStringSensor("brooklyn.test.stringAttribute", "Brooklyn testing string attribute");
+    private BasicAttributeSensor<Map> mapAttribute = new BasicAttributeSensor<Map>(Map.class, "brooklyn.test.mapAttribute", "Brooklyn testing map attribute");
+    private String objectName = "Brooklyn:type=MyTestMBean,name=myname";
+    private ObjectName jmxObjectName;
+    private String attributeName = "myattrib";
+    private String opName = "myop";
+    
+    public static class TestEntityWithJmx extends TestEntityImpl {
+        @Override public void init() {
+            setAttribute(Attributes.HOSTNAME, "localhost");
+            setAttribute(UsesJmx.JMX_PORT, 
+                    LocalhostMachineProvisioningLocation.obtainPort(PortRanges.fromString("40123+")));
+            // only supports no-agent, at the moment
+            setConfig(UsesJmx.JMX_AGENT_MODE, JmxAgentModes.NONE);
+            setAttribute(UsesJmx.RMI_REGISTRY_PORT, -1);  // -1 means to use the JMX_PORT only
+            ConfigToAttributes.apply(this, UsesJmx.JMX_CONTEXT);
+        }
+    }
+    
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        jmxObjectName = new ObjectName(objectName);
+        
+        // Create an entity and configure it with the above JMX service
+        app = TestApplication.Factory.newManagedInstanceForTests();
+        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class).impl(TestEntityWithJmx.class));
+        app.start(ImmutableList.of(new SimulatedLocation()));
+
+        jmxHelper = new JmxHelper(entity);
+        
+        jmxService = new JmxService(entity);
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (feed != null) feed.stop();
+        if (jmxHelper != null) jmxHelper.disconnect();
+        if (jmxService != null) jmxService.shutdown();
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+        feed = null;
+    }
+
+    @Test
+    public void testJmxAttributePollerReturnsMBeanAttribute() throws Exception {
+        GeneralisedDynamicMBean mbean = jmxService.registerMBean(ImmutableMap.of(attributeName, 42), objectName);
+
+        feed = JmxFeed.builder()
+                .entity(entity)
+                .pollAttribute(new JmxAttributePollConfig<Integer>(intAttribute)
+                        .objectName(objectName)
+                        .period(50)
+                        .attributeName(attributeName))
+                .build();
+        
+        // Starts with value defined when registering...
+        assertSensorEventually(intAttribute, 42, TIMEOUT_MS);
+
+        // Change the value and check it updates
+        mbean.updateAttributeValue(attributeName, 64);
+        assertSensorEventually(intAttribute, 64, TIMEOUT_MS);
+    }
+
+    @Test
+    public void testJmxAttributeOfTypeTabularDataProviderConvertedToMap() throws Exception {
+        // Create the CompositeType and TabularData
+        CompositeType compositeType = new CompositeType(
+                "typeName",
+                "description",
+                new String[] {"myint", "mystring", "mybool"},    // item names
+                new String[] {"myint", "mystring", "mybool"},    // item descriptions, can't be null or empty string
+                new OpenType<?>[] {SimpleType.INTEGER, SimpleType.STRING, SimpleType.BOOLEAN}
+        );
+        TabularType tt = new TabularType(
+                "typeName",
+                "description",
+                compositeType,
+                new String[] {"myint"}
+        );
+        TabularDataSupport tds = new TabularDataSupport(tt);
+        tds.put(new CompositeDataSupport(
+                compositeType,
+                new String[] {"mybool", "myint", "mystring"},
+                new Object[] {true, 1234, "on"}
+        ));
+
+        // Create MBean
+        GeneralisedDynamicMBean mbean = jmxService.registerMBean(ImmutableMap.of(attributeName, tds), objectName);
+
+        feed = JmxFeed.builder()
+                .entity(entity)
+                .pollAttribute(new JmxAttributePollConfig<Map>(mapAttribute)
+                        .objectName(objectName)
+                        .attributeName(attributeName)
+                        .onSuccess((Function)JmxValueFunctions.tabularDataToMap()))
+                .build();
+
+        // Starts with value defined when registering...
+        assertSensorEventually(
+                mapAttribute, 
+                ImmutableMap.of("myint", 1234, "mystring", "on", "mybool", Boolean.TRUE), 
+                TIMEOUT_MS);
+    }
+
+    @Test
+    public void testJmxOperationPolledForSensor() throws Exception {
+        // This is awful syntax...
+        final int opReturnVal = 123;
+        final AtomicInteger invocationCount = new AtomicInteger();
+        MBeanOperationInfo opInfo = new MBeanOperationInfo(opName, "my descr", new MBeanParameterInfo[0], Integer.class.getName(), MBeanOperationInfo.ACTION);
+        GeneralisedDynamicMBean mbean = jmxService.registerMBean(
+                Collections.emptyMap(), 
+                ImmutableMap.of(opInfo, new Function<Object[], Integer>() {
+                        public Integer apply(Object[] args) {
+                            invocationCount.incrementAndGet(); return opReturnVal;
+                        }}),
+                objectName);
+
+        feed = JmxFeed.builder()
+                .entity(entity)
+                .pollOperation(new JmxOperationPollConfig<Integer>(intAttribute)
+                        .objectName(objectName)
+                        .operationName(opName))
+                .build();
+        
+        TestUtils.executeUntilSucceeds(ImmutableMap.of("timeout", TIMEOUT_MS), new Runnable() {
+            public void run() {
+                assertTrue(invocationCount.get() > 0, "invocationCount="+invocationCount);
+                assertEquals(entity.getAttribute(intAttribute), (Integer)opReturnVal);
+            }});
+    }
+
+    @Test
+    public void testJmxOperationWithArgPolledForSensor() throws Exception {
+        // This is awful syntax...
+        MBeanParameterInfo paramInfo = new MBeanParameterInfo("param1", String.class.getName(), "my param1");
+        MBeanParameterInfo[] paramInfos = new MBeanParameterInfo[] {paramInfo};
+        MBeanOperationInfo opInfo = new MBeanOperationInfo(opName, "my descr", paramInfos, String.class.getName(), MBeanOperationInfo.ACTION);
+        GeneralisedDynamicMBean mbean = jmxService.registerMBean(
+                Collections.emptyMap(), 
+                ImmutableMap.of(opInfo, new Function<Object[], String>() {
+                        public String apply(Object[] args) {
+                            return args[0]+"suffix";
+                        }}),
+                objectName);
+        
+        feed = JmxFeed.builder()
+                .entity(entity)
+                .pollOperation(new JmxOperationPollConfig<String>(stringAttribute)
+                        .objectName(objectName)
+                        .operationName(opName)
+                        .operationParams(ImmutableList.of("myprefix")))
+                .build();
+        
+        assertSensorEventually(stringAttribute, "myprefix"+"suffix", TIMEOUT_MS);
+    }
+
+    @Test
+    public void testJmxNotificationSubscriptionForSensor() throws Exception {
+        final String one = "notification.one", two = "notification.two";
+        final StandardEmitterMBean mbean = jmxService.registerMBean(ImmutableList.of(one, two), objectName);
+        final AtomicInteger sequence = new AtomicInteger(0);
+
+        feed = JmxFeed.builder()
+                .entity(entity)
+                .subscribeToNotification(new JmxNotificationSubscriptionConfig<Integer>(intAttribute)
+                        .objectName(objectName)
+                        .notificationFilter(JmxNotificationFilters.matchesType(one)))
+                .build();        
+
+        // Notification updates the sensor
+        // Note that subscription is done async, so can't just send notification immediately during test.
+        Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), new Runnable() {
+            public void run() {
+                sendNotification(mbean, one, sequence.getAndIncrement(), 123);
+                assertEquals(entity.getAttribute(intAttribute), (Integer)123);
+            }});
+        
+        // But other notification types are ignored
+        sendNotification(mbean, two, sequence.getAndIncrement(), -1);
+            
+        Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), new Runnable() {
+            public void run() {
+                assertEquals(entity.getAttribute(intAttribute), (Integer)123);
+            }});
+    }
+    
+    @Test
+    public void testJmxNotificationSubscriptionForSensorParsingNotification() throws Exception {
+        final String one = "notification.one", two = "notification.two";
+        final StandardEmitterMBean mbean = jmxService.registerMBean(ImmutableList.of(one, two), objectName);
+        final AtomicInteger sequence = new AtomicInteger(0);
+        
+        feed = JmxFeed.builder()
+                .entity(entity)
+                .subscribeToNotification(new JmxNotificationSubscriptionConfig<Integer>(intAttribute)
+                        .objectName(objectName)
+                        .notificationFilter(JmxNotificationFilters.matchesType(one))
+                        .onNotification(new Function<Notification, Integer>() {
+                            public Integer apply(Notification notif) {
+                                return (Integer) notif.getUserData();
+                            }
+                        }))
+                .build();
+        
+        
+        // Notification updates the sensor
+        // Note that subscription is done async, so can't just send notification immediately during test.
+        Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), new Runnable() {
+            public void run() {
+                sendNotification(mbean, one, sequence.getAndIncrement(), 123);
+                assertEquals(entity.getAttribute(intAttribute), (Integer)123);
+            }});
+    }
+
+    @Test
+    public void testJmxNotificationMultipleSubscriptionUsingListener() throws Exception {
+        final String one = "notification.one";
+        final String two = "notification.two";
+        final StandardEmitterMBean mbean = jmxService.registerMBean(ImmutableList.of(one, two), objectName);
+        final AtomicInteger sequence = new AtomicInteger(0);
+
+        feed = JmxFeed.builder()
+                .entity(entity)
+                .subscribeToNotification(new JmxNotificationSubscriptionConfig<Integer>(intAttribute)
+                        .objectName(objectName)
+                        .notificationFilter(JmxNotificationFilters.matchesTypes(one, two)))
+                .build();
+        
+        // Notification updates the sensor
+        // Note that subscription is done async, so can't just send notification immediately during test.
+        Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), new Runnable() {
+            public void run() {
+                sendNotification(mbean, one, sequence.getAndIncrement(), 123);
+                assertEquals(entity.getAttribute(intAttribute), (Integer)123);
+            }});
+
+        // And wildcard means other notifications also received
+        sendNotification(mbean, two, sequence.getAndIncrement(), 456);
+        assertSensorEventually(intAttribute, 456, TIMEOUT_MS);
+    }
+
+    // Test reproduces functionality used in Monterey, for Venue entity being told of requestActor
+    @Test
+    public void testSubscribeToJmxNotificationAndEmitCorrespondingNotificationSensor() throws Exception {
+        TestApplication app2 = new TestApplicationImpl();
+        final EntityWithEmitter entity = new EntityWithEmitter(app2);
+        Entities.startManagement(app2);
+        try {
+            app2.start(ImmutableList.of(new SimulatedLocation()));
+            
+            final List<SensorEvent<String>> received = Lists.newArrayList();
+            app2.subscribe(null, EntityWithEmitter.MY_NOTIF, new SensorEventListener<String>() {
+                public void onEvent(SensorEvent<String> event) {
+                    received.add(event);
+                }});
+    
+            final StandardEmitterMBean mbean = jmxService.registerMBean(ImmutableList.of("one"), objectName);
+            final AtomicInteger sequence = new AtomicInteger(0);
+            
+            jmxHelper.connect(TIMEOUT_MS);
+            jmxHelper.addNotificationListener(jmxObjectName, new NotificationListener() {
+                    public void handleNotification(Notification notif, Object callback) {
+                        if (notif.getType().equals("one")) {
+                            entity.emit(EntityWithEmitter.MY_NOTIF, (String) notif.getUserData());
+                        }
+                    }});
+            
+
+            Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), new Runnable() {
+                public void run() {
+                    sendNotification(mbean, "one", sequence.getAndIncrement(), "abc");
+                    assertTrue(received.size() > 0, "received size should be bigger than 0");
+                    assertEquals(received.get(0).getValue(), "abc");
+                }});
+        } finally {
+            Entities.destroyAll(app2.getManagementContext());
+        }
+    }
+    
+    public static class EntityWithEmitter extends AbstractEntity {
+        public static final BasicNotificationSensor<String> MY_NOTIF = new BasicNotificationSensor<String>(String.class, "test.myNotif", "My notif");
+        
+        public EntityWithEmitter(Entity owner) {
+            super(owner);
+        }
+        public EntityWithEmitter(Map flags) {
+            super(flags);
+        }
+        public EntityWithEmitter(Map flags, Entity owner) {
+            super(flags, owner);
+        }
+    }
+    
+    private Notification sendNotification(StandardEmitterMBean mbean, String type, long seq, Object userData) {
+        Notification notif = new Notification(type, mbean, seq);
+        notif.setUserData(userData);
+        mbean.sendNotification(notif);
+        return notif;
+    }
+    
+    private <T> void assertSensorEventually(final AttributeSensor<T> sensor, final T expectedVal, long timeout) {
+        executeUntilSucceeds(ImmutableMap.of("timeout", timeout), new Callable<Void>() {
+            public Void call() {
+                assertEquals(entity.getAttribute(sensor), expectedVal);
+                return null;
+            }});
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/test/java/org/apache/brooklyn/feed/jmx/JmxHelperTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/feed/jmx/JmxHelperTest.java b/software/base/src/test/java/org/apache/brooklyn/feed/jmx/JmxHelperTest.java
new file mode 100644
index 0000000..3470166
--- /dev/null
+++ b/software/base/src/test/java/org/apache/brooklyn/feed/jmx/JmxHelperTest.java
@@ -0,0 +1,311 @@
+/*
+ * 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.feed.jmx;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.fail;
+
+import java.io.IOException;
+import java.util.List;
+
+import javax.management.DynamicMBean;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.StandardEmitterMBean;
+
+import org.apache.brooklyn.entity.software.base.test.jmx.GeneralisedDynamicMBean;
+import org.apache.brooklyn.entity.software.base.test.jmx.JmxService;
+import org.apache.brooklyn.feed.jmx.JmxHelper;
+import org.apache.brooklyn.test.TestUtils;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.jclouds.util.Throwables2;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.testng.collections.Lists;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class JmxHelperTest {
+
+    private static final Logger log = LoggerFactory.getLogger(JmxHelperTest.class);
+    
+    private static final String LOCALHOST_NAME = "localhost";
+    
+    private static final int TIMEOUT_MS = 5000;
+    private static final int SHORT_WAIT_MS = 250;
+
+    private JmxService jmxService;
+    private JmxHelper jmxHelper;
+    
+    private String objectName = "Brooklyn:type=MyTestMBean,name=myname";
+    private String objectNameWithWildcard = "Brooklyn:type=MyTestMBean,name=mynam*";
+    private ObjectName jmxObjectName;
+    private ObjectName jmxObjectNameWithWildcard;
+    private String attributeName = "myattrib";
+    private String opName = "myop";
+    
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        jmxObjectName = new ObjectName(objectName);
+        jmxObjectNameWithWildcard = new ObjectName(objectNameWithWildcard);
+        jmxService = newJmxServiceRetrying(LOCALHOST_NAME, 5);
+        jmxHelper = new JmxHelper(jmxService.getUrl());
+        jmxHelper.setMinTimeBetweenReconnectAttempts(0);
+        jmxHelper.connect(TIMEOUT_MS);
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (jmxHelper != null) jmxHelper.disconnect();
+        if (jmxService != null) jmxService.shutdown();
+        jmxHelper = null;
+        jmxService = null;
+    }
+
+    @Test
+    public void testGetAttribute() throws Exception {
+        GeneralisedDynamicMBean mbean = jmxService.registerMBean(MutableMap.of("myattr", "myval"), objectName);
+        assertEquals(jmxHelper.getAttribute(jmxObjectName, "myattr"), "myval");
+    }
+
+    @Test
+    public void testGetAttributeUsingObjectNameWildcard() throws Exception {
+        GeneralisedDynamicMBean mbean = jmxService.registerMBean(MutableMap.of("myattr", "myval"), objectName);
+        assertEquals(jmxHelper.getAttribute(jmxObjectNameWithWildcard, "myattr"), "myval");
+    }
+
+    @Test
+    public void testSetAttribute() throws Exception {
+        DynamicMBean mbean = jmxService.registerMBean(MutableMap.of("myattr", "myval"), objectName);
+
+        jmxHelper.setAttribute(jmxObjectName, "myattr", "abc");
+        Object actual = jmxHelper.getAttribute(jmxObjectName, "myattr");
+        assertEquals(actual, "abc");
+    }
+
+    @Test
+    public void testSetAttributeUsingObjectNameWildcard() throws Exception {
+        DynamicMBean mbean = jmxService.registerMBean(MutableMap.of("myattr", "myval"), objectName);
+
+        jmxHelper.setAttribute(jmxObjectNameWithWildcard, "myattr", "abc");
+        Object actual = jmxHelper.getAttribute(jmxObjectName, "myattr");
+        assertEquals(actual, "abc");
+    }
+
+    @Test
+    public void testInvokeOperationWithNoArgs() throws Exception {
+        final String opReturnVal = "my result";
+        MBeanOperationInfo opInfo = new MBeanOperationInfo(opName, "my descr", new MBeanParameterInfo[0], String.class.getName(), MBeanOperationInfo.ACTION);
+        Function<Object[], String> opImpl = new Function<Object[], String>() {
+            @Override public String apply(Object[] args) {
+                assertEquals(args.length, 0, "args="+args);
+                return opReturnVal;
+            }
+        };
+        GeneralisedDynamicMBean mbean = jmxService.registerMBean(ImmutableMap.of(), ImmutableMap.of(opInfo, opImpl), objectName);
+        
+        assertEquals(jmxHelper.operation(objectName, opName), opReturnVal);
+    }
+
+    @Test
+    public void testInvokeOperationUsingObjectNameWildcard() throws Exception {
+        final String opReturnVal = "my result";
+        MBeanOperationInfo opInfo = new MBeanOperationInfo(opName, "my descr", new MBeanParameterInfo[0], String.class.getName(), MBeanOperationInfo.ACTION);
+        Function<Object[], String> opImpl = new Function<Object[], String>() {
+            @Override public String apply(Object[] args) {
+                assertEquals(args.length, 0, "args="+args);
+                return opReturnVal;
+            }
+        };
+        GeneralisedDynamicMBean mbean = jmxService.registerMBean(ImmutableMap.of(), ImmutableMap.of(opInfo, opImpl), objectName);
+        
+        assertEquals(jmxHelper.operation(objectNameWithWildcard, opName), opReturnVal);
+    }
+
+    @Test
+    public void testInvokeOperationWithArgs() throws Exception {
+        final String opReturnPrefix = "my result prefix/";
+        String opParam1 = "my param 1";
+        MBeanOperationInfo opInfo = new MBeanOperationInfo(
+                opName, 
+                "my descr", 
+                new MBeanParameterInfo[] {new MBeanParameterInfo("myParam1", String.class.getName(), "my param1 descr")}, 
+                String.class.getName(), 
+                MBeanOperationInfo.ACTION);
+        Function<Object[],String> opImpl = new Function<Object[],String>() {
+            public String apply(Object[] input) {
+                return opReturnPrefix+input[0];
+            }
+        };
+        GeneralisedDynamicMBean mbean = jmxService.registerMBean(ImmutableMap.of(), ImmutableMap.of(opInfo, opImpl), objectName);
+        
+        assertEquals(jmxHelper.operation(objectName, opName, opParam1), opReturnPrefix+opParam1);
+    }
+
+    @Test
+    public void testReconnectsOnJmxServerTemporaryFailure() throws Exception {
+        int port = jmxService.getJmxPort();
+        GeneralisedDynamicMBean mbean = jmxService.registerMBean(MutableMap.of("myattr", "myval"), objectName);
+        assertEquals(jmxHelper.getAttribute(jmxObjectName, "myattr"), "myval");
+        
+        // Simulate temporary network-failure
+        jmxService.shutdown();
+
+        // Ensure that we have a failed query while the "network is down"         
+        try {
+            jmxHelper.getAttribute(jmxObjectName, attributeName);
+            fail();
+        } catch (Exception e) {
+            if (Throwables2.getFirstThrowableOfType(e, IOException.class) == null) {
+                throw e;
+            }
+        }
+
+        // Simulate the network restarting
+        jmxService = new JmxService(LOCALHOST_NAME, port);
+        
+        GeneralisedDynamicMBean mbean2 = jmxService.registerMBean(MutableMap.of("myattr", "myval2"), objectName);
+        assertEquals(jmxHelper.getAttribute(jmxObjectName, "myattr"), "myval2");
+    }
+    
+    @Test(expectedExceptions = {IllegalStateException.class})
+    public void testJmxCheckInstanceExistsEventuallyThrowsIfNotFound() throws Exception {
+        jmxHelper.assertMBeanExistsEventually(new ObjectName("Brooklyn:type=DoesNotExist,name=doesNotExist"), 1L);
+    }
+
+    @Test
+    public void testJmxObjectCheckExistsEventuallyReturnsIfFoundImmediately() throws Exception {
+        GeneralisedDynamicMBean mbean = jmxService.registerMBean(objectName);
+        jmxHelper.assertMBeanExistsEventually(jmxObjectName, 1L);
+    }
+
+    @Test
+    public void testJmxObjectCheckExistsEventuallyTakingLongReturnsIfFoundImmediately() throws Exception {
+        GeneralisedDynamicMBean mbean = jmxService.registerMBean(objectName);
+        jmxHelper.assertMBeanExistsEventually(jmxObjectName, 1L);
+    }
+
+    @Test
+    public void testJmxObjectCheckExistsEventuallyReturnsIfCreatedDuringPolling() throws Exception {
+        Thread t = new Thread(new Runnable() {
+                public void run() {
+                    try {
+                        Thread.sleep(SHORT_WAIT_MS);
+                        GeneralisedDynamicMBean mbean = jmxService.registerMBean(objectName);
+                    } catch (InterruptedException e) {
+                        return; // graceful return
+                    } catch (Exception e) {
+                        throw Exceptions.propagate(e);
+                    }
+                }});
+        try {
+            t.start();
+            
+            jmxHelper.assertMBeanExistsEventually(jmxObjectName, TIMEOUT_MS);
+        } finally {
+            t.interrupt();
+            t.join(TIMEOUT_MS);
+            assertFalse(t.isAlive());
+        }        
+    }
+
+    @Test
+    public void testSubscribeToJmxNotificationsDirectlyWithJmxHelper() throws Exception {
+        StandardEmitterMBean mbean = jmxService.registerMBean(ImmutableList.of("one"), objectName);
+        int sequence = 0;
+        final List<Notification> received = Lists.newArrayList();
+
+        jmxHelper.addNotificationListener(jmxObjectName, new NotificationListener() {
+            public void handleNotification(Notification notif, Object callback) {
+                received.add(notif);
+            }});
+                    
+
+        final Notification notif = sendNotification(mbean, "one", sequence++, "abc");
+
+        TestUtils.executeUntilSucceeds(ImmutableMap.of("timeout", TIMEOUT_MS), new Runnable() {
+            public void run() {
+                assertEquals(received.size(), 1);
+                assertNotificationsEqual(received.get(0), notif);
+            }});
+    }
+
+    // Visual-inspection test that LOG.warn happens only once; TODO setup a listener to the logging output
+    @Test
+    public void testMBeanNotFoundLoggedOnlyOncePerUrl() throws Exception {
+        ObjectName wrongObjectName = new ObjectName("DoesNotExist:type=DoesNotExist");
+
+        // Expect just one log message about:
+        //     JMX object DoesNotExist:type=DoesNotExist not found at service:jmx:rmi://localhost:1099/jndi/rmi://localhost:9001/jmxrmi"
+        for (int i = 0; i < 10; i++) {
+            jmxHelper.findMBean(wrongObjectName);
+        }
+
+        jmxService.shutdown();
+        jmxHelper.disconnect();
+        
+        jmxService = newJmxServiceRetrying(LOCALHOST_NAME, 5);
+        jmxHelper = new JmxHelper(jmxService.getUrl());
+        jmxHelper.connect();
+        
+        // Expect just one log message about:
+        //     JMX object DoesNotExist:type=DoesNotExist not found at service:jmx:rmi://localhost:1099/jndi/rmi://localhost:9001/jmxrmi"
+        for (int i = 0; i < 10; i++) {
+            jmxHelper.findMBean(wrongObjectName);
+        }
+    }
+
+    private JmxService newJmxServiceRetrying(String host, int retries) throws Exception {
+        Exception lastexception = null;
+        for (int i = 0; i < retries; i++) {
+            try {
+                return new JmxService(host, (int)(11000+(500*Math.random())));
+            } catch (Exception e) {
+                log.debug("Unable to create JMX service during test - "+retries+" retries remaining");
+                lastexception = e;
+            }
+        }
+        throw lastexception;
+    }
+
+    private Notification sendNotification(StandardEmitterMBean mbean, String type, long seq, Object userData) {
+        Notification notif = new Notification(type, mbean, seq);
+        notif.setUserData(userData);
+        mbean.sendNotification(notif);
+        return notif;
+    }
+    
+    private void assertNotificationsEqual(Notification n1, Notification n2) {
+        assertEquals(n1.getType(), n2.getType());
+        assertEquals(n1.getSequenceNumber(), n2.getSequenceNumber());
+        assertEquals(n1.getUserData(), n2.getUserData());
+        assertEquals(n1.getTimeStamp(), n2.getTimeStamp());
+        assertEquals(n1.getMessage(), n2.getMessage());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/test/java/org/apache/brooklyn/feed/jmx/RebindJmxFeedTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/feed/jmx/RebindJmxFeedTest.java b/software/base/src/test/java/org/apache/brooklyn/feed/jmx/RebindJmxFeedTest.java
new file mode 100644
index 0000000..f521932
--- /dev/null
+++ b/software/base/src/test/java/org/apache/brooklyn/feed/jmx/RebindJmxFeedTest.java
@@ -0,0 +1,148 @@
+/*
+ * 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.feed.jmx;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Collection;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.Feed;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.feed.ConfigToAttributes;
+import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.mgmt.rebind.RebindTestFixtureWithApp;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.core.test.entity.TestEntityImpl;
+import org.apache.brooklyn.entity.java.UsesJmx;
+import org.apache.brooklyn.entity.java.UsesJmx.JmxAgentModes;
+import org.apache.brooklyn.entity.software.base.test.jmx.GeneralisedDynamicMBean;
+import org.apache.brooklyn.entity.software.base.test.jmx.JmxService;
+import org.apache.brooklyn.feed.jmx.JmxAttributePollConfig;
+import org.apache.brooklyn.feed.jmx.JmxFeed;
+import org.apache.brooklyn.feed.jmx.JmxHelper;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+public class RebindJmxFeedTest extends RebindTestFixtureWithApp {
+
+    private static final Logger log = LoggerFactory.getLogger(RebindJmxFeedTest.class);
+
+    private static final String LOCALHOST_NAME = "localhost";
+
+    static final AttributeSensor<String> SENSOR_STRING = Sensors.newStringSensor("aString", "");
+    static final AttributeSensor<Integer> SENSOR_INT = Sensors.newIntegerSensor( "aLong", "");
+
+    static final String JMX_ATTRIBUTE_NAME = "myattr";
+    static final String OBJECT_NAME = "Brooklyn:type=MyTestMBean,name=myname";
+    
+    private JmxService jmxService;
+    
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        
+        // Create an entity and configure it with the above JMX service
+        //jmxService = newJmxServiceRetrying(LOCALHOST_NAME, 5);
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    @Override
+    public void tearDown() throws Exception {
+        if (jmxService != null) jmxService.shutdown();
+        super.tearDown();
+    }
+
+    @Test
+    public void testJmxFeedIsPersisted() throws Exception {
+        runJmxFeedIsPersisted(false);
+    }
+
+    @Test
+    public void testJmxFeedIsPersistedWithPreCreatedJmxHelper() throws Exception {
+        runJmxFeedIsPersisted(true);
+    }
+
+    protected void runJmxFeedIsPersisted(boolean preCreateJmxHelper) throws Exception {
+        TestEntity origEntity = origApp.createAndManageChild(EntitySpec.create(TestEntity.class).impl(MyEntityWithJmxFeedImpl.class)
+                .configure(MyEntityWithJmxFeedImpl.PRE_CREATE_JMX_HELPER, preCreateJmxHelper));
+        origApp.start(ImmutableList.<Location>of());
+        
+        jmxService = new JmxService(origEntity);
+        GeneralisedDynamicMBean mbean = jmxService.registerMBean(MutableMap.of(JMX_ATTRIBUTE_NAME, "myval"), OBJECT_NAME);
+        
+        EntityTestUtils.assertAttributeEqualsEventually(origEntity, SENSOR_STRING, "myval");
+        assertEquals(origEntity.feeds().getFeeds().size(), 1);
+
+        newApp = rebind();
+        TestEntity newEntity = (TestEntity) Iterables.getOnlyElement(newApp.getChildren());
+        
+        Collection<Feed> newFeeds = newEntity.feeds().getFeeds();
+        assertEquals(newFeeds.size(), 1);
+        
+        // Expect the feed to still be polling
+        newEntity.setAttribute(SENSOR_STRING, null);
+        EntityTestUtils.assertAttributeEqualsEventually(newEntity, SENSOR_STRING, "myval");
+    }
+
+    public static class MyEntityWithJmxFeedImpl extends TestEntityImpl {
+        public static final ConfigKey<Boolean> PRE_CREATE_JMX_HELPER = ConfigKeys.newBooleanConfigKey("test.rebindjmx.preCreateJmxHelper", "", false);
+        
+        @Override
+        public void start(Collection<? extends Location> locs) {
+            // TODO Auto-generated method stub
+            super.start(locs);
+            
+            setAttribute(Attributes.HOSTNAME, "localhost");
+            setAttribute(UsesJmx.JMX_PORT, 
+                    LocalhostMachineProvisioningLocation.obtainPort(PortRanges.fromString("40123+")));
+            // only supports no-agent, at the moment
+            setConfig(UsesJmx.JMX_AGENT_MODE, JmxAgentModes.NONE);
+            setAttribute(UsesJmx.RMI_REGISTRY_PORT, -1);  // -1 means to use the JMX_PORT only
+            ConfigToAttributes.apply(this, UsesJmx.JMX_CONTEXT);
+            
+            JmxFeed.Builder feedBuilder = JmxFeed.builder()
+                    .entity(this)
+                    .pollAttribute(new JmxAttributePollConfig<String>(SENSOR_STRING)
+                            .objectName(OBJECT_NAME)
+                            .period(50)
+                            .attributeName(JMX_ATTRIBUTE_NAME));
+            if (getConfig(PRE_CREATE_JMX_HELPER)) {
+                JmxHelper jmxHelper = new JmxHelper(this);
+                feedBuilder.helper(jmxHelper);
+            }
+            addFeed(feedBuilder.build());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/JmxFeedTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/JmxFeedTest.java b/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/JmxFeedTest.java
deleted file mode 100644
index 8f722b2..0000000
--- a/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/JmxFeedTest.java
+++ /dev/null
@@ -1,422 +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.feed.jmx;
-
-import static org.apache.brooklyn.test.TestUtils.executeUntilSucceeds;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.management.MBeanOperationInfo;
-import javax.management.MBeanParameterInfo;
-import javax.management.Notification;
-import javax.management.NotificationListener;
-import javax.management.ObjectName;
-import javax.management.StandardEmitterMBean;
-import javax.management.openmbean.CompositeDataSupport;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.OpenType;
-import javax.management.openmbean.SimpleType;
-import javax.management.openmbean.TabularDataSupport;
-import javax.management.openmbean.TabularType;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.api.sensor.SensorEvent;
-import org.apache.brooklyn.api.sensor.SensorEventListener;
-import org.apache.brooklyn.core.entity.AbstractEntity;
-import org.apache.brooklyn.core.entity.Attributes;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.location.PortRanges;
-import org.apache.brooklyn.core.location.SimulatedLocation;
-import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
-import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
-import org.apache.brooklyn.core.sensor.Sensors;
-import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.apache.brooklyn.core.test.entity.TestApplicationImpl;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.core.test.entity.TestEntityImpl;
-import org.apache.brooklyn.entity.java.JmxSupport;
-import org.apache.brooklyn.entity.java.UsesJmx;
-import org.apache.brooklyn.entity.java.UsesJmx.JmxAgentModes;
-import org.apache.brooklyn.entity.software.base.test.jmx.GeneralisedDynamicMBean;
-import org.apache.brooklyn.entity.software.base.test.jmx.JmxService;
-import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
-import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;
-import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
-import org.apache.brooklyn.sensor.feed.jmx.JmxHelper;
-import org.apache.brooklyn.sensor.feed.jmx.JmxNotificationFilters;
-import org.apache.brooklyn.sensor.feed.jmx.JmxNotificationSubscriptionConfig;
-import org.apache.brooklyn.sensor.feed.jmx.JmxOperationPollConfig;
-import org.apache.brooklyn.sensor.feed.jmx.JmxValueFunctions;
-import org.apache.brooklyn.test.Asserts;
-import org.apache.brooklyn.test.TestUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-import org.testng.collections.Lists;
-import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
-
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-/**
- * Test the operation of the {@link JmxFeed} class.
- * <p>
- * Also confirm some of the JMX setup done by {@link JmxSupport} and {@link JmxHelper},
- * based on ports in {@link UsesJmx}.
- * <p>
- * TODO tests of other JMX_AGENT_MODE are done in ActiveMqIntegrationTest; 
- * would be nice to promote some to live here
- */
-public class JmxFeedTest {
-    
-    // FIXME Move out the JmxHelper tests into the JmxHelperTest class
-    
-    // FIXME Also test that setting poll period takes effect
-    
-    private static final Logger log = LoggerFactory.getLogger(JmxFeedTest.class);
-
-    private static final int TIMEOUT_MS = 5000;
-    private static final int SHORT_WAIT_MS = 250;
-    
-    private JmxService jmxService;
-    private TestApplication app;
-    private TestEntity entity;
-    private JmxFeed feed;
-    private JmxHelper jmxHelper;
-    
-    private AttributeSensor<Integer> intAttribute = Sensors.newIntegerSensor("brooklyn.test.intAttribute", "Brooklyn testing int attribute");
-    private AttributeSensor<String> stringAttribute = Sensors.newStringSensor("brooklyn.test.stringAttribute", "Brooklyn testing string attribute");
-    private BasicAttributeSensor<Map> mapAttribute = new BasicAttributeSensor<Map>(Map.class, "brooklyn.test.mapAttribute", "Brooklyn testing map attribute");
-    private String objectName = "Brooklyn:type=MyTestMBean,name=myname";
-    private ObjectName jmxObjectName;
-    private String attributeName = "myattrib";
-    private String opName = "myop";
-    
-    public static class TestEntityWithJmx extends TestEntityImpl {
-        @Override public void init() {
-            setAttribute(Attributes.HOSTNAME, "localhost");
-            setAttribute(UsesJmx.JMX_PORT, 
-                    LocalhostMachineProvisioningLocation.obtainPort(PortRanges.fromString("40123+")));
-            // only supports no-agent, at the moment
-            setConfig(UsesJmx.JMX_AGENT_MODE, JmxAgentModes.NONE);
-            setAttribute(UsesJmx.RMI_REGISTRY_PORT, -1);  // -1 means to use the JMX_PORT only
-            ConfigToAttributes.apply(this, UsesJmx.JMX_CONTEXT);
-        }
-    }
-    
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() throws Exception {
-        jmxObjectName = new ObjectName(objectName);
-        
-        // Create an entity and configure it with the above JMX service
-        app = TestApplication.Factory.newManagedInstanceForTests();
-        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class).impl(TestEntityWithJmx.class));
-        app.start(ImmutableList.of(new SimulatedLocation()));
-
-        jmxHelper = new JmxHelper(entity);
-        
-        jmxService = new JmxService(entity);
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        if (feed != null) feed.stop();
-        if (jmxHelper != null) jmxHelper.disconnect();
-        if (jmxService != null) jmxService.shutdown();
-        if (app != null) Entities.destroyAll(app.getManagementContext());
-        feed = null;
-    }
-
-    @Test
-    public void testJmxAttributePollerReturnsMBeanAttribute() throws Exception {
-        GeneralisedDynamicMBean mbean = jmxService.registerMBean(ImmutableMap.of(attributeName, 42), objectName);
-
-        feed = JmxFeed.builder()
-                .entity(entity)
-                .pollAttribute(new JmxAttributePollConfig<Integer>(intAttribute)
-                        .objectName(objectName)
-                        .period(50)
-                        .attributeName(attributeName))
-                .build();
-        
-        // Starts with value defined when registering...
-        assertSensorEventually(intAttribute, 42, TIMEOUT_MS);
-
-        // Change the value and check it updates
-        mbean.updateAttributeValue(attributeName, 64);
-        assertSensorEventually(intAttribute, 64, TIMEOUT_MS);
-    }
-
-    @Test
-    public void testJmxAttributeOfTypeTabularDataProviderConvertedToMap() throws Exception {
-        // Create the CompositeType and TabularData
-        CompositeType compositeType = new CompositeType(
-                "typeName",
-                "description",
-                new String[] {"myint", "mystring", "mybool"},    // item names
-                new String[] {"myint", "mystring", "mybool"},    // item descriptions, can't be null or empty string
-                new OpenType<?>[] {SimpleType.INTEGER, SimpleType.STRING, SimpleType.BOOLEAN}
-        );
-        TabularType tt = new TabularType(
-                "typeName",
-                "description",
-                compositeType,
-                new String[] {"myint"}
-        );
-        TabularDataSupport tds = new TabularDataSupport(tt);
-        tds.put(new CompositeDataSupport(
-                compositeType,
-                new String[] {"mybool", "myint", "mystring"},
-                new Object[] {true, 1234, "on"}
-        ));
-
-        // Create MBean
-        GeneralisedDynamicMBean mbean = jmxService.registerMBean(ImmutableMap.of(attributeName, tds), objectName);
-
-        feed = JmxFeed.builder()
-                .entity(entity)
-                .pollAttribute(new JmxAttributePollConfig<Map>(mapAttribute)
-                        .objectName(objectName)
-                        .attributeName(attributeName)
-                        .onSuccess((Function)JmxValueFunctions.tabularDataToMap()))
-                .build();
-
-        // Starts with value defined when registering...
-        assertSensorEventually(
-                mapAttribute, 
-                ImmutableMap.of("myint", 1234, "mystring", "on", "mybool", Boolean.TRUE), 
-                TIMEOUT_MS);
-    }
-
-    @Test
-    public void testJmxOperationPolledForSensor() throws Exception {
-        // This is awful syntax...
-        final int opReturnVal = 123;
-        final AtomicInteger invocationCount = new AtomicInteger();
-        MBeanOperationInfo opInfo = new MBeanOperationInfo(opName, "my descr", new MBeanParameterInfo[0], Integer.class.getName(), MBeanOperationInfo.ACTION);
-        GeneralisedDynamicMBean mbean = jmxService.registerMBean(
-                Collections.emptyMap(), 
-                ImmutableMap.of(opInfo, new Function<Object[], Integer>() {
-                        public Integer apply(Object[] args) {
-                            invocationCount.incrementAndGet(); return opReturnVal;
-                        }}),
-                objectName);
-
-        feed = JmxFeed.builder()
-                .entity(entity)
-                .pollOperation(new JmxOperationPollConfig<Integer>(intAttribute)
-                        .objectName(objectName)
-                        .operationName(opName))
-                .build();
-        
-        TestUtils.executeUntilSucceeds(ImmutableMap.of("timeout", TIMEOUT_MS), new Runnable() {
-            public void run() {
-                assertTrue(invocationCount.get() > 0, "invocationCount="+invocationCount);
-                assertEquals(entity.getAttribute(intAttribute), (Integer)opReturnVal);
-            }});
-    }
-
-    @Test
-    public void testJmxOperationWithArgPolledForSensor() throws Exception {
-        // This is awful syntax...
-        MBeanParameterInfo paramInfo = new MBeanParameterInfo("param1", String.class.getName(), "my param1");
-        MBeanParameterInfo[] paramInfos = new MBeanParameterInfo[] {paramInfo};
-        MBeanOperationInfo opInfo = new MBeanOperationInfo(opName, "my descr", paramInfos, String.class.getName(), MBeanOperationInfo.ACTION);
-        GeneralisedDynamicMBean mbean = jmxService.registerMBean(
-                Collections.emptyMap(), 
-                ImmutableMap.of(opInfo, new Function<Object[], String>() {
-                        public String apply(Object[] args) {
-                            return args[0]+"suffix";
-                        }}),
-                objectName);
-        
-        feed = JmxFeed.builder()
-                .entity(entity)
-                .pollOperation(new JmxOperationPollConfig<String>(stringAttribute)
-                        .objectName(objectName)
-                        .operationName(opName)
-                        .operationParams(ImmutableList.of("myprefix")))
-                .build();
-        
-        assertSensorEventually(stringAttribute, "myprefix"+"suffix", TIMEOUT_MS);
-    }
-
-    @Test
-    public void testJmxNotificationSubscriptionForSensor() throws Exception {
-        final String one = "notification.one", two = "notification.two";
-        final StandardEmitterMBean mbean = jmxService.registerMBean(ImmutableList.of(one, two), objectName);
-        final AtomicInteger sequence = new AtomicInteger(0);
-
-        feed = JmxFeed.builder()
-                .entity(entity)
-                .subscribeToNotification(new JmxNotificationSubscriptionConfig<Integer>(intAttribute)
-                        .objectName(objectName)
-                        .notificationFilter(JmxNotificationFilters.matchesType(one)))
-                .build();        
-
-        // Notification updates the sensor
-        // Note that subscription is done async, so can't just send notification immediately during test.
-        Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), new Runnable() {
-            public void run() {
-                sendNotification(mbean, one, sequence.getAndIncrement(), 123);
-                assertEquals(entity.getAttribute(intAttribute), (Integer)123);
-            }});
-        
-        // But other notification types are ignored
-        sendNotification(mbean, two, sequence.getAndIncrement(), -1);
-            
-        Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), new Runnable() {
-            public void run() {
-                assertEquals(entity.getAttribute(intAttribute), (Integer)123);
-            }});
-    }
-    
-    @Test
-    public void testJmxNotificationSubscriptionForSensorParsingNotification() throws Exception {
-        final String one = "notification.one", two = "notification.two";
-        final StandardEmitterMBean mbean = jmxService.registerMBean(ImmutableList.of(one, two), objectName);
-        final AtomicInteger sequence = new AtomicInteger(0);
-        
-        feed = JmxFeed.builder()
-                .entity(entity)
-                .subscribeToNotification(new JmxNotificationSubscriptionConfig<Integer>(intAttribute)
-                        .objectName(objectName)
-                        .notificationFilter(JmxNotificationFilters.matchesType(one))
-                        .onNotification(new Function<Notification, Integer>() {
-                            public Integer apply(Notification notif) {
-                                return (Integer) notif.getUserData();
-                            }
-                        }))
-                .build();
-        
-        
-        // Notification updates the sensor
-        // Note that subscription is done async, so can't just send notification immediately during test.
-        Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), new Runnable() {
-            public void run() {
-                sendNotification(mbean, one, sequence.getAndIncrement(), 123);
-                assertEquals(entity.getAttribute(intAttribute), (Integer)123);
-            }});
-    }
-
-    @Test
-    public void testJmxNotificationMultipleSubscriptionUsingListener() throws Exception {
-        final String one = "notification.one";
-        final String two = "notification.two";
-        final StandardEmitterMBean mbean = jmxService.registerMBean(ImmutableList.of(one, two), objectName);
-        final AtomicInteger sequence = new AtomicInteger(0);
-
-        feed = JmxFeed.builder()
-                .entity(entity)
-                .subscribeToNotification(new JmxNotificationSubscriptionConfig<Integer>(intAttribute)
-                        .objectName(objectName)
-                        .notificationFilter(JmxNotificationFilters.matchesTypes(one, two)))
-                .build();
-        
-        // Notification updates the sensor
-        // Note that subscription is done async, so can't just send notification immediately during test.
-        Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), new Runnable() {
-            public void run() {
-                sendNotification(mbean, one, sequence.getAndIncrement(), 123);
-                assertEquals(entity.getAttribute(intAttribute), (Integer)123);
-            }});
-
-        // And wildcard means other notifications also received
-        sendNotification(mbean, two, sequence.getAndIncrement(), 456);
-        assertSensorEventually(intAttribute, 456, TIMEOUT_MS);
-    }
-
-    // Test reproduces functionality used in Monterey, for Venue entity being told of requestActor
-    @Test
-    public void testSubscribeToJmxNotificationAndEmitCorrespondingNotificationSensor() throws Exception {
-        TestApplication app2 = new TestApplicationImpl();
-        final EntityWithEmitter entity = new EntityWithEmitter(app2);
-        Entities.startManagement(app2);
-        try {
-            app2.start(ImmutableList.of(new SimulatedLocation()));
-            
-            final List<SensorEvent<String>> received = Lists.newArrayList();
-            app2.subscribe(null, EntityWithEmitter.MY_NOTIF, new SensorEventListener<String>() {
-                public void onEvent(SensorEvent<String> event) {
-                    received.add(event);
-                }});
-    
-            final StandardEmitterMBean mbean = jmxService.registerMBean(ImmutableList.of("one"), objectName);
-            final AtomicInteger sequence = new AtomicInteger(0);
-            
-            jmxHelper.connect(TIMEOUT_MS);
-            jmxHelper.addNotificationListener(jmxObjectName, new NotificationListener() {
-                    public void handleNotification(Notification notif, Object callback) {
-                        if (notif.getType().equals("one")) {
-                            entity.emit(EntityWithEmitter.MY_NOTIF, (String) notif.getUserData());
-                        }
-                    }});
-            
-
-            Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), new Runnable() {
-                public void run() {
-                    sendNotification(mbean, "one", sequence.getAndIncrement(), "abc");
-                    assertTrue(received.size() > 0, "received size should be bigger than 0");
-                    assertEquals(received.get(0).getValue(), "abc");
-                }});
-        } finally {
-            Entities.destroyAll(app2.getManagementContext());
-        }
-    }
-    
-    public static class EntityWithEmitter extends AbstractEntity {
-        public static final BasicNotificationSensor<String> MY_NOTIF = new BasicNotificationSensor<String>(String.class, "test.myNotif", "My notif");
-        
-        public EntityWithEmitter(Entity owner) {
-            super(owner);
-        }
-        public EntityWithEmitter(Map flags) {
-            super(flags);
-        }
-        public EntityWithEmitter(Map flags, Entity owner) {
-            super(flags, owner);
-        }
-    }
-    
-    private Notification sendNotification(StandardEmitterMBean mbean, String type, long seq, Object userData) {
-        Notification notif = new Notification(type, mbean, seq);
-        notif.setUserData(userData);
-        mbean.sendNotification(notif);
-        return notif;
-    }
-    
-    private <T> void assertSensorEventually(final AttributeSensor<T> sensor, final T expectedVal, long timeout) {
-        executeUntilSucceeds(ImmutableMap.of("timeout", timeout), new Callable<Void>() {
-            public Void call() {
-                assertEquals(entity.getAttribute(sensor), expectedVal);
-                return null;
-            }});
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/JmxHelperTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/JmxHelperTest.java b/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/JmxHelperTest.java
deleted file mode 100644
index 058947c..0000000
--- a/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/JmxHelperTest.java
+++ /dev/null
@@ -1,311 +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.feed.jmx;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.fail;
-
-import java.io.IOException;
-import java.util.List;
-
-import javax.management.DynamicMBean;
-import javax.management.MBeanOperationInfo;
-import javax.management.MBeanParameterInfo;
-import javax.management.Notification;
-import javax.management.NotificationListener;
-import javax.management.ObjectName;
-import javax.management.StandardEmitterMBean;
-
-import org.apache.brooklyn.entity.software.base.test.jmx.GeneralisedDynamicMBean;
-import org.apache.brooklyn.entity.software.base.test.jmx.JmxService;
-import org.apache.brooklyn.sensor.feed.jmx.JmxHelper;
-import org.apache.brooklyn.test.TestUtils;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.jclouds.util.Throwables2;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-import org.testng.collections.Lists;
-
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-public class JmxHelperTest {
-
-    private static final Logger log = LoggerFactory.getLogger(JmxHelperTest.class);
-    
-    private static final String LOCALHOST_NAME = "localhost";
-    
-    private static final int TIMEOUT_MS = 5000;
-    private static final int SHORT_WAIT_MS = 250;
-
-    private JmxService jmxService;
-    private JmxHelper jmxHelper;
-    
-    private String objectName = "Brooklyn:type=MyTestMBean,name=myname";
-    private String objectNameWithWildcard = "Brooklyn:type=MyTestMBean,name=mynam*";
-    private ObjectName jmxObjectName;
-    private ObjectName jmxObjectNameWithWildcard;
-    private String attributeName = "myattrib";
-    private String opName = "myop";
-    
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() throws Exception {
-        jmxObjectName = new ObjectName(objectName);
-        jmxObjectNameWithWildcard = new ObjectName(objectNameWithWildcard);
-        jmxService = newJmxServiceRetrying(LOCALHOST_NAME, 5);
-        jmxHelper = new JmxHelper(jmxService.getUrl());
-        jmxHelper.setMinTimeBetweenReconnectAttempts(0);
-        jmxHelper.connect(TIMEOUT_MS);
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        if (jmxHelper != null) jmxHelper.disconnect();
-        if (jmxService != null) jmxService.shutdown();
-        jmxHelper = null;
-        jmxService = null;
-    }
-
-    @Test
-    public void testGetAttribute() throws Exception {
-        GeneralisedDynamicMBean mbean = jmxService.registerMBean(MutableMap.of("myattr", "myval"), objectName);
-        assertEquals(jmxHelper.getAttribute(jmxObjectName, "myattr"), "myval");
-    }
-
-    @Test
-    public void testGetAttributeUsingObjectNameWildcard() throws Exception {
-        GeneralisedDynamicMBean mbean = jmxService.registerMBean(MutableMap.of("myattr", "myval"), objectName);
-        assertEquals(jmxHelper.getAttribute(jmxObjectNameWithWildcard, "myattr"), "myval");
-    }
-
-    @Test
-    public void testSetAttribute() throws Exception {
-        DynamicMBean mbean = jmxService.registerMBean(MutableMap.of("myattr", "myval"), objectName);
-
-        jmxHelper.setAttribute(jmxObjectName, "myattr", "abc");
-        Object actual = jmxHelper.getAttribute(jmxObjectName, "myattr");
-        assertEquals(actual, "abc");
-    }
-
-    @Test
-    public void testSetAttributeUsingObjectNameWildcard() throws Exception {
-        DynamicMBean mbean = jmxService.registerMBean(MutableMap.of("myattr", "myval"), objectName);
-
-        jmxHelper.setAttribute(jmxObjectNameWithWildcard, "myattr", "abc");
-        Object actual = jmxHelper.getAttribute(jmxObjectName, "myattr");
-        assertEquals(actual, "abc");
-    }
-
-    @Test
-    public void testInvokeOperationWithNoArgs() throws Exception {
-        final String opReturnVal = "my result";
-        MBeanOperationInfo opInfo = new MBeanOperationInfo(opName, "my descr", new MBeanParameterInfo[0], String.class.getName(), MBeanOperationInfo.ACTION);
-        Function<Object[], String> opImpl = new Function<Object[], String>() {
-            @Override public String apply(Object[] args) {
-                assertEquals(args.length, 0, "args="+args);
-                return opReturnVal;
-            }
-        };
-        GeneralisedDynamicMBean mbean = jmxService.registerMBean(ImmutableMap.of(), ImmutableMap.of(opInfo, opImpl), objectName);
-        
-        assertEquals(jmxHelper.operation(objectName, opName), opReturnVal);
-    }
-
-    @Test
-    public void testInvokeOperationUsingObjectNameWildcard() throws Exception {
-        final String opReturnVal = "my result";
-        MBeanOperationInfo opInfo = new MBeanOperationInfo(opName, "my descr", new MBeanParameterInfo[0], String.class.getName(), MBeanOperationInfo.ACTION);
-        Function<Object[], String> opImpl = new Function<Object[], String>() {
-            @Override public String apply(Object[] args) {
-                assertEquals(args.length, 0, "args="+args);
-                return opReturnVal;
-            }
-        };
-        GeneralisedDynamicMBean mbean = jmxService.registerMBean(ImmutableMap.of(), ImmutableMap.of(opInfo, opImpl), objectName);
-        
-        assertEquals(jmxHelper.operation(objectNameWithWildcard, opName), opReturnVal);
-    }
-
-    @Test
-    public void testInvokeOperationWithArgs() throws Exception {
-        final String opReturnPrefix = "my result prefix/";
-        String opParam1 = "my param 1";
-        MBeanOperationInfo opInfo = new MBeanOperationInfo(
-                opName, 
-                "my descr", 
-                new MBeanParameterInfo[] {new MBeanParameterInfo("myParam1", String.class.getName(), "my param1 descr")}, 
-                String.class.getName(), 
-                MBeanOperationInfo.ACTION);
-        Function<Object[],String> opImpl = new Function<Object[],String>() {
-            public String apply(Object[] input) {
-                return opReturnPrefix+input[0];
-            }
-        };
-        GeneralisedDynamicMBean mbean = jmxService.registerMBean(ImmutableMap.of(), ImmutableMap.of(opInfo, opImpl), objectName);
-        
-        assertEquals(jmxHelper.operation(objectName, opName, opParam1), opReturnPrefix+opParam1);
-    }
-
-    @Test
-    public void testReconnectsOnJmxServerTemporaryFailure() throws Exception {
-        int port = jmxService.getJmxPort();
-        GeneralisedDynamicMBean mbean = jmxService.registerMBean(MutableMap.of("myattr", "myval"), objectName);
-        assertEquals(jmxHelper.getAttribute(jmxObjectName, "myattr"), "myval");
-        
-        // Simulate temporary network-failure
-        jmxService.shutdown();
-
-        // Ensure that we have a failed query while the "network is down"         
-        try {
-            jmxHelper.getAttribute(jmxObjectName, attributeName);
-            fail();
-        } catch (Exception e) {
-            if (Throwables2.getFirstThrowableOfType(e, IOException.class) == null) {
-                throw e;
-            }
-        }
-
-        // Simulate the network restarting
-        jmxService = new JmxService(LOCALHOST_NAME, port);
-        
-        GeneralisedDynamicMBean mbean2 = jmxService.registerMBean(MutableMap.of("myattr", "myval2"), objectName);
-        assertEquals(jmxHelper.getAttribute(jmxObjectName, "myattr"), "myval2");
-    }
-    
-    @Test(expectedExceptions = {IllegalStateException.class})
-    public void testJmxCheckInstanceExistsEventuallyThrowsIfNotFound() throws Exception {
-        jmxHelper.assertMBeanExistsEventually(new ObjectName("Brooklyn:type=DoesNotExist,name=doesNotExist"), 1L);
-    }
-
-    @Test
-    public void testJmxObjectCheckExistsEventuallyReturnsIfFoundImmediately() throws Exception {
-        GeneralisedDynamicMBean mbean = jmxService.registerMBean(objectName);
-        jmxHelper.assertMBeanExistsEventually(jmxObjectName, 1L);
-    }
-
-    @Test
-    public void testJmxObjectCheckExistsEventuallyTakingLongReturnsIfFoundImmediately() throws Exception {
-        GeneralisedDynamicMBean mbean = jmxService.registerMBean(objectName);
-        jmxHelper.assertMBeanExistsEventually(jmxObjectName, 1L);
-    }
-
-    @Test
-    public void testJmxObjectCheckExistsEventuallyReturnsIfCreatedDuringPolling() throws Exception {
-        Thread t = new Thread(new Runnable() {
-                public void run() {
-                    try {
-                        Thread.sleep(SHORT_WAIT_MS);
-                        GeneralisedDynamicMBean mbean = jmxService.registerMBean(objectName);
-                    } catch (InterruptedException e) {
-                        return; // graceful return
-                    } catch (Exception e) {
-                        throw Exceptions.propagate(e);
-                    }
-                }});
-        try {
-            t.start();
-            
-            jmxHelper.assertMBeanExistsEventually(jmxObjectName, TIMEOUT_MS);
-        } finally {
-            t.interrupt();
-            t.join(TIMEOUT_MS);
-            assertFalse(t.isAlive());
-        }        
-    }
-
-    @Test
-    public void testSubscribeToJmxNotificationsDirectlyWithJmxHelper() throws Exception {
-        StandardEmitterMBean mbean = jmxService.registerMBean(ImmutableList.of("one"), objectName);
-        int sequence = 0;
-        final List<Notification> received = Lists.newArrayList();
-
-        jmxHelper.addNotificationListener(jmxObjectName, new NotificationListener() {
-            public void handleNotification(Notification notif, Object callback) {
-                received.add(notif);
-            }});
-                    
-
-        final Notification notif = sendNotification(mbean, "one", sequence++, "abc");
-
-        TestUtils.executeUntilSucceeds(ImmutableMap.of("timeout", TIMEOUT_MS), new Runnable() {
-            public void run() {
-                assertEquals(received.size(), 1);
-                assertNotificationsEqual(received.get(0), notif);
-            }});
-    }
-
-    // Visual-inspection test that LOG.warn happens only once; TODO setup a listener to the logging output
-    @Test
-    public void testMBeanNotFoundLoggedOnlyOncePerUrl() throws Exception {
-        ObjectName wrongObjectName = new ObjectName("DoesNotExist:type=DoesNotExist");
-
-        // Expect just one log message about:
-        //     JMX object DoesNotExist:type=DoesNotExist not found at service:jmx:rmi://localhost:1099/jndi/rmi://localhost:9001/jmxrmi"
-        for (int i = 0; i < 10; i++) {
-            jmxHelper.findMBean(wrongObjectName);
-        }
-
-        jmxService.shutdown();
-        jmxHelper.disconnect();
-        
-        jmxService = newJmxServiceRetrying(LOCALHOST_NAME, 5);
-        jmxHelper = new JmxHelper(jmxService.getUrl());
-        jmxHelper.connect();
-        
-        // Expect just one log message about:
-        //     JMX object DoesNotExist:type=DoesNotExist not found at service:jmx:rmi://localhost:1099/jndi/rmi://localhost:9001/jmxrmi"
-        for (int i = 0; i < 10; i++) {
-            jmxHelper.findMBean(wrongObjectName);
-        }
-    }
-
-    private JmxService newJmxServiceRetrying(String host, int retries) throws Exception {
-        Exception lastexception = null;
-        for (int i = 0; i < retries; i++) {
-            try {
-                return new JmxService(host, (int)(11000+(500*Math.random())));
-            } catch (Exception e) {
-                log.debug("Unable to create JMX service during test - "+retries+" retries remaining");
-                lastexception = e;
-            }
-        }
-        throw lastexception;
-    }
-
-    private Notification sendNotification(StandardEmitterMBean mbean, String type, long seq, Object userData) {
-        Notification notif = new Notification(type, mbean, seq);
-        notif.setUserData(userData);
-        mbean.sendNotification(notif);
-        return notif;
-    }
-    
-    private void assertNotificationsEqual(Notification n1, Notification n2) {
-        assertEquals(n1.getType(), n2.getType());
-        assertEquals(n1.getSequenceNumber(), n2.getSequenceNumber());
-        assertEquals(n1.getUserData(), n2.getUserData());
-        assertEquals(n1.getTimeStamp(), n2.getTimeStamp());
-        assertEquals(n1.getMessage(), n2.getMessage());
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/RebindJmxFeedTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/RebindJmxFeedTest.java b/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/RebindJmxFeedTest.java
deleted file mode 100644
index 9ed0031..0000000
--- a/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/RebindJmxFeedTest.java
+++ /dev/null
@@ -1,148 +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.feed.jmx;
-
-import static org.testng.Assert.assertEquals;
-
-import java.util.Collection;
-
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.api.sensor.Feed;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.entity.Attributes;
-import org.apache.brooklyn.core.location.PortRanges;
-import org.apache.brooklyn.core.mgmt.rebind.RebindTestFixtureWithApp;
-import org.apache.brooklyn.core.sensor.Sensors;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.core.test.entity.TestEntityImpl;
-import org.apache.brooklyn.entity.java.UsesJmx;
-import org.apache.brooklyn.entity.java.UsesJmx.JmxAgentModes;
-import org.apache.brooklyn.entity.software.base.test.jmx.GeneralisedDynamicMBean;
-import org.apache.brooklyn.entity.software.base.test.jmx.JmxService;
-import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
-import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;
-import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
-import org.apache.brooklyn.sensor.feed.jmx.JmxHelper;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-
-public class RebindJmxFeedTest extends RebindTestFixtureWithApp {
-
-    private static final Logger log = LoggerFactory.getLogger(RebindJmxFeedTest.class);
-
-    private static final String LOCALHOST_NAME = "localhost";
-
-    static final AttributeSensor<String> SENSOR_STRING = Sensors.newStringSensor("aString", "");
-    static final AttributeSensor<Integer> SENSOR_INT = Sensors.newIntegerSensor( "aLong", "");
-
-    static final String JMX_ATTRIBUTE_NAME = "myattr";
-    static final String OBJECT_NAME = "Brooklyn:type=MyTestMBean,name=myname";
-    
-    private JmxService jmxService;
-    
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        
-        // Create an entity and configure it with the above JMX service
-        //jmxService = newJmxServiceRetrying(LOCALHOST_NAME, 5);
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    @Override
-    public void tearDown() throws Exception {
-        if (jmxService != null) jmxService.shutdown();
-        super.tearDown();
-    }
-
-    @Test
-    public void testJmxFeedIsPersisted() throws Exception {
-        runJmxFeedIsPersisted(false);
-    }
-
-    @Test
-    public void testJmxFeedIsPersistedWithPreCreatedJmxHelper() throws Exception {
-        runJmxFeedIsPersisted(true);
-    }
-
-    protected void runJmxFeedIsPersisted(boolean preCreateJmxHelper) throws Exception {
-        TestEntity origEntity = origApp.createAndManageChild(EntitySpec.create(TestEntity.class).impl(MyEntityWithJmxFeedImpl.class)
-                .configure(MyEntityWithJmxFeedImpl.PRE_CREATE_JMX_HELPER, preCreateJmxHelper));
-        origApp.start(ImmutableList.<Location>of());
-        
-        jmxService = new JmxService(origEntity);
-        GeneralisedDynamicMBean mbean = jmxService.registerMBean(MutableMap.of(JMX_ATTRIBUTE_NAME, "myval"), OBJECT_NAME);
-        
-        EntityTestUtils.assertAttributeEqualsEventually(origEntity, SENSOR_STRING, "myval");
-        assertEquals(origEntity.feeds().getFeeds().size(), 1);
-
-        newApp = rebind();
-        TestEntity newEntity = (TestEntity) Iterables.getOnlyElement(newApp.getChildren());
-        
-        Collection<Feed> newFeeds = newEntity.feeds().getFeeds();
-        assertEquals(newFeeds.size(), 1);
-        
-        // Expect the feed to still be polling
-        newEntity.setAttribute(SENSOR_STRING, null);
-        EntityTestUtils.assertAttributeEqualsEventually(newEntity, SENSOR_STRING, "myval");
-    }
-
-    public static class MyEntityWithJmxFeedImpl extends TestEntityImpl {
-        public static final ConfigKey<Boolean> PRE_CREATE_JMX_HELPER = ConfigKeys.newBooleanConfigKey("test.rebindjmx.preCreateJmxHelper", "", false);
-        
-        @Override
-        public void start(Collection<? extends Location> locs) {
-            // TODO Auto-generated method stub
-            super.start(locs);
-            
-            setAttribute(Attributes.HOSTNAME, "localhost");
-            setAttribute(UsesJmx.JMX_PORT, 
-                    LocalhostMachineProvisioningLocation.obtainPort(PortRanges.fromString("40123+")));
-            // only supports no-agent, at the moment
-            setConfig(UsesJmx.JMX_AGENT_MODE, JmxAgentModes.NONE);
-            setAttribute(UsesJmx.RMI_REGISTRY_PORT, -1);  // -1 means to use the JMX_PORT only
-            ConfigToAttributes.apply(this, UsesJmx.JMX_CONTEXT);
-            
-            JmxFeed.Builder feedBuilder = JmxFeed.builder()
-                    .entity(this)
-                    .pollAttribute(new JmxAttributePollConfig<String>(SENSOR_STRING)
-                            .objectName(OBJECT_NAME)
-                            .period(50)
-                            .attributeName(JMX_ATTRIBUTE_NAME));
-            if (getConfig(PRE_CREATE_JMX_HELPER)) {
-                JmxHelper jmxHelper = new JmxHelper(this);
-                feedBuilder.helper(jmxHelper);
-            }
-            addFeed(feedBuilder.build());
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeImpl.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeImpl.java
index 8b544c4..f78ddba 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeImpl.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeImpl.java
@@ -22,11 +22,11 @@ import org.apache.brooklyn.core.config.render.RendererHints;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.entity.java.JavaAppUtils;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
+import org.apache.brooklyn.feed.jmx.JmxFeed;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
-import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
 import org.apache.brooklyn.util.guava.Functionals;
 
 public class CrateNodeImpl extends SoftwareProcessImpl implements CrateNode{

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java
index 3d8c982..c23c616 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java
@@ -23,10 +23,10 @@ import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.core.effector.EffectorBody;
 import org.apache.brooklyn.core.location.Locations;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
+import org.apache.brooklyn.feed.ssh.SshFeed;
+import org.apache.brooklyn.feed.ssh.SshPollConfig;
+import org.apache.brooklyn.feed.ssh.SshPollValue;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.feed.ssh.SshFeed;
-import org.apache.brooklyn.sensor.feed.ssh.SshPollConfig;
-import org.apache.brooklyn.sensor.feed.ssh.SshPollValue;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.text.Identifiers;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterImpl.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterImpl.java
index e106728..d6527ca 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterImpl.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterImpl.java
@@ -39,9 +39,9 @@ import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceNotUpL
 import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.group.DynamicClusterImpl;
+import org.apache.brooklyn.feed.function.FunctionFeed;
+import org.apache.brooklyn.feed.function.FunctionPollConfig;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
-import org.apache.brooklyn.sensor.feed.function.FunctionFeed;
-import org.apache.brooklyn.sensor.feed.function.FunctionPollConfig;
 import org.apache.brooklyn.util.collections.CollectionFunctionals;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
 import org.apache.brooklyn.util.core.task.TaskBuilder;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNodeImpl.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNodeImpl.java
index 71c73c6..5346fcb 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNodeImpl.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNodeImpl.java
@@ -24,12 +24,12 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.core.effector.EffectorBody;
 import org.apache.brooklyn.core.location.Locations;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
+import org.apache.brooklyn.feed.ssh.SshFeed;
+import org.apache.brooklyn.feed.ssh.SshPollConfig;
+import org.apache.brooklyn.feed.ssh.SshPollValue;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.feed.ssh.SshFeed;
-import org.apache.brooklyn.sensor.feed.ssh.SshPollConfig;
-import org.apache.brooklyn.sensor.feed.ssh.SshPollValue;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.guava.Maybe;



[15/36] incubator-brooklyn git commit: Rename o.a.b.sensor.core to o.a.b.core.sensor

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/sensor/DependentConfiguration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/DependentConfiguration.java b/core/src/main/java/org/apache/brooklyn/core/sensor/DependentConfiguration.java
new file mode 100644
index 0000000..b909856
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/sensor/DependentConfiguration.java
@@ -0,0 +1,823 @@
+/*
+ * 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.core.sensor;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import groovy.lang.Closure;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.mgmt.ExecutionContext;
+import org.apache.brooklyn.api.mgmt.SubscriptionHandle;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.api.mgmt.TaskAdaptable;
+import org.apache.brooklyn.api.mgmt.TaskFactory;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+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.entity.Attributes;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.util.collections.CollectionFunctionals;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.task.BasicExecutionContext;
+import org.apache.brooklyn.util.core.task.BasicTask;
+import org.apache.brooklyn.util.core.task.DeferredSupplier;
+import org.apache.brooklyn.util.core.task.DynamicTasks;
+import org.apache.brooklyn.util.core.task.ParallelTask;
+import org.apache.brooklyn.util.core.task.TaskInternal;
+import org.apache.brooklyn.util.core.task.Tasks;
+import org.apache.brooklyn.util.core.task.ValueResolver;
+import org.apache.brooklyn.util.exceptions.CompoundRuntimeException;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.exceptions.NotManagedException;
+import org.apache.brooklyn.util.exceptions.RuntimeTimeoutException;
+import org.apache.brooklyn.util.groovy.GroovyJavaMethods;
+import org.apache.brooklyn.util.guava.Functionals;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.text.Strings;
+import org.apache.brooklyn.util.time.CountdownTimer;
+import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+/** Conveniences for making tasks which run in entity {@link ExecutionContext}s, subscribing to attributes from other entities, possibly transforming those;
+ * these {@link Task} instances are typically passed in {@link EntityLocal#setConfig(ConfigKey, Object)}.
+ * <p>
+ * If using a lot it may be useful to:
+ * <pre>
+ * {@code
+ *   import static brooklyn.event.basic.DependentConfiguration.*;
+ * }
+ * </pre>
+ */
+public class DependentConfiguration {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DependentConfiguration.class);
+    
+    //not instantiable, only a static helper
+    private DependentConfiguration() {}
+
+    /**
+     * Default readiness is Groovy truth.
+     * 
+     * @see #attributeWhenReady(Entity, AttributeSensor, Predicate)
+     */
+    public static <T> Task<T> attributeWhenReady(Entity source, AttributeSensor<T> sensor) {
+        return attributeWhenReady(source, sensor, GroovyJavaMethods.truthPredicate());
+    }
+    
+    public static <T> Task<T> attributeWhenReady(Entity source, AttributeSensor<T> sensor, Closure<Boolean> ready) {
+        Predicate<Object> readyPredicate = (ready != null) ? GroovyJavaMethods.<Object>predicateFromClosure(ready) : GroovyJavaMethods.truthPredicate();
+        return attributeWhenReady(source, sensor, readyPredicate);
+    }
+    
+    /** returns an unsubmitted {@link Task} which blocks until the given sensor on the given source entity gives a value that satisfies ready, then returns that value;
+     * particular useful in Entity configuration where config will block until Tasks have a value
+     */
+    public static <T> Task<T> attributeWhenReady(final Entity source, final AttributeSensor<T> sensor, final Predicate<? super T> ready) {
+        Builder<T, T> builder = builder().attributeWhenReady(source, sensor);
+        if (ready != null) builder.readiness(ready);
+        return builder.build();
+
+    }
+
+    public static <T,V> Task<V> attributePostProcessedWhenReady(Entity source, AttributeSensor<T> sensor, Closure<Boolean> ready, Closure<V> postProcess) {
+        Predicate<? super T> readyPredicate = (ready != null) ? GroovyJavaMethods.predicateFromClosure(ready) : GroovyJavaMethods.truthPredicate();
+        Function<? super T, V> postProcessFunction = GroovyJavaMethods.<T,V>functionFromClosure(postProcess);
+        return attributePostProcessedWhenReady(source, sensor, readyPredicate, postProcessFunction);
+    }
+
+    public static <T,V> Task<V> attributePostProcessedWhenReady(Entity source, AttributeSensor<T> sensor, Closure<V> postProcess) {
+        return attributePostProcessedWhenReady(source, sensor, GroovyJavaMethods.truthPredicate(), GroovyJavaMethods.<T,V>functionFromClosure(postProcess));
+    }
+
+    public static <T> Task<T> valueWhenAttributeReady(Entity source, AttributeSensor<T> sensor, T value) {
+        return DependentConfiguration.<T,T>attributePostProcessedWhenReady(source, sensor, GroovyJavaMethods.truthPredicate(), Functions.constant(value));
+    }
+
+    public static <T,V> Task<V> valueWhenAttributeReady(Entity source, AttributeSensor<T> sensor, Function<? super T,V> valueProvider) {
+        return attributePostProcessedWhenReady(source, sensor, GroovyJavaMethods.truthPredicate(), valueProvider);
+    }
+    
+    public static <T,V> Task<V> valueWhenAttributeReady(Entity source, AttributeSensor<T> sensor, Closure<V> valueProvider) {
+        return attributePostProcessedWhenReady(source, sensor, GroovyJavaMethods.truthPredicate(), valueProvider);
+    }
+    
+    public static <T,V> Task<V> attributePostProcessedWhenReady(final Entity source, final AttributeSensor<T> sensor, final Predicate<? super T> ready, final Closure<V> postProcess) {
+        return attributePostProcessedWhenReady(source, sensor, ready, GroovyJavaMethods.<T,V>functionFromClosure(postProcess));
+    }
+    
+    @SuppressWarnings("unchecked")
+    public static <T,V> Task<V> attributePostProcessedWhenReady(final Entity source, final AttributeSensor<T> sensor, final Predicate<? super T> ready, final Function<? super T,V> postProcess) {
+        Builder<T,T> builder1 = DependentConfiguration.builder().attributeWhenReady(source, sensor);
+        // messy generics here to support null postProcess; would be nice to disallow that here
+        Builder<T,V> builder;
+        if (postProcess != null) {
+            builder = builder1.postProcess(postProcess);
+        } else {
+            builder = (Builder<T,V>)builder1;
+        }
+        if (ready != null) builder.readiness(ready);
+        
+        return builder.build();
+    }
+
+    public static <T> T waitInTaskForAttributeReady(Entity source, AttributeSensor<T> sensor, Predicate<? super T> ready) {
+        return waitInTaskForAttributeReady(source, sensor, ready, ImmutableList.<AttributeAndSensorCondition<?>>of());
+    }
+
+    public static <T> T waitInTaskForAttributeReady(final Entity source, final AttributeSensor<T> sensor, Predicate<? super T> ready, List<AttributeAndSensorCondition<?>> abortConditions) {
+        String blockingDetails = "Waiting for ready from "+source+" "+sensor+" (subscription)";
+        return waitInTaskForAttributeReady(source, sensor, ready, abortConditions, blockingDetails);
+    }
+    
+    // TODO would be nice to have an easy semantics for whenServiceUp (cf DynamicWebAppClusterImpl.whenServiceUp)
+    
+    public static <T> T waitInTaskForAttributeReady(final Entity source, final AttributeSensor<T> sensor, Predicate<? super T> ready, List<AttributeAndSensorCondition<?>> abortConditions, String blockingDetails) {
+        return new WaitInTaskForAttributeReady<T,T>(source, sensor, ready, abortConditions, blockingDetails).call();
+    }
+    
+    protected static class WaitInTaskForAttributeReady<T,V> implements Callable<V> {
+
+        /* This is a change since before Oct 2014. Previously it would continue to poll,
+         * (maybe finding a different error) if the target entity becomes unmanaged. 
+         * Now it actively checks unmanaged by default, and still throws although it might 
+         * now find a different problem. */
+        private final static boolean DEFAULT_IGNORE_UNMANAGED = false;
+        
+        protected final Entity source;
+        protected final AttributeSensor<T> sensor;
+        protected final Predicate<? super T> ready;
+        protected final List<AttributeAndSensorCondition<?>> abortSensorConditions;
+        protected final String blockingDetails;
+        protected final Function<? super T,? extends V> postProcess;
+        protected final Duration timeout;
+        protected final Maybe<V> onTimeout;
+        protected final boolean ignoreUnmanaged;
+        protected final Maybe<V> onUnmanaged;
+        // TODO onError Continue / Throw / Return(V)
+        
+        protected WaitInTaskForAttributeReady(Builder<T, V> builder) {
+            this.source = builder.source;
+            this.sensor = builder.sensor;
+            this.ready = builder.readiness;
+            this.abortSensorConditions = builder.abortSensorConditions;
+            this.blockingDetails = builder.blockingDetails;
+            this.postProcess = builder.postProcess;
+            this.timeout = builder.timeout;
+            this.onTimeout = builder.onTimeout;
+            this.ignoreUnmanaged = builder.ignoreUnmanaged;
+            this.onUnmanaged = builder.onUnmanaged;
+        }
+        
+        private WaitInTaskForAttributeReady(Entity source, AttributeSensor<T> sensor, Predicate<? super T> ready,
+                List<AttributeAndSensorCondition<?>> abortConditions, String blockingDetails) {
+            this.source = source;
+            this.sensor = sensor;
+            this.ready = ready;
+            this.abortSensorConditions = abortConditions;
+            this.blockingDetails = blockingDetails;
+            
+            this.timeout = Duration.PRACTICALLY_FOREVER;
+            this.onTimeout = Maybe.absent();
+            this.ignoreUnmanaged = DEFAULT_IGNORE_UNMANAGED;
+            this.onUnmanaged = Maybe.absent();
+            this.postProcess = null;
+        }
+
+        @SuppressWarnings("unchecked")
+        protected V postProcess(T value) {
+            if (this.postProcess!=null) return postProcess.apply(value);
+            // if no post-processing assume the types are correct
+            return (V) value;
+        }
+        
+        protected boolean ready(T value) {
+            if (ready!=null) return ready.apply(value);
+            return GroovyJavaMethods.truth(value);
+        }
+        
+        @SuppressWarnings({ "rawtypes", "unchecked" })
+        @Override
+        public V call() {
+            T value = source.getAttribute(sensor);
+
+            // return immediately if either the ready predicate or the abort conditions hold
+            if (ready(value)) return postProcess(value);
+
+            final List<Exception> abortionExceptions = Lists.newCopyOnWriteArrayList();
+            long start = System.currentTimeMillis();
+            
+            for (AttributeAndSensorCondition abortCondition : abortSensorConditions) {
+                Object abortValue = abortCondition.source.getAttribute(abortCondition.sensor);
+                if (abortCondition.predicate.apply(abortValue)) {
+                    abortionExceptions.add(new Exception("Abort due to "+abortCondition.source+" -> "+abortCondition.sensor));
+                }
+            }
+            if (abortionExceptions.size() > 0) {
+                throw new CompoundRuntimeException("Aborted waiting for ready from "+source+" "+sensor, abortionExceptions);
+            }
+
+            TaskInternal<?> current = (TaskInternal<?>) Tasks.current();
+            if (current == null) throw new IllegalStateException("Should only be invoked in a running task");
+            Entity entity = BrooklynTaskTags.getTargetOrContextEntity(current);
+            if (entity == null) throw new IllegalStateException("Should only be invoked in a running task with an entity tag; "+
+                current+" has no entity tag ("+current.getStatusDetail(false)+")");
+            
+            final LinkedList<T> publishedValues = new LinkedList<T>();
+            final Semaphore semaphore = new Semaphore(0); // could use Exchanger
+            SubscriptionHandle subscription = null;
+            List<SubscriptionHandle> abortSubscriptions = Lists.newArrayList();
+            
+            try {
+                subscription = ((EntityInternal)entity).getSubscriptionContext().subscribe(source, sensor, new SensorEventListener<T>() {
+                    @Override public void onEvent(SensorEvent<T> event) {
+                        synchronized (publishedValues) { publishedValues.add(event.getValue()); }
+                        semaphore.release();
+                    }});
+                for (final AttributeAndSensorCondition abortCondition : abortSensorConditions) {
+                    abortSubscriptions.add(((EntityInternal)entity).getSubscriptionContext().subscribe(abortCondition.source, abortCondition.sensor, new SensorEventListener<Object>() {
+                        @Override public void onEvent(SensorEvent<Object> event) {
+                            if (abortCondition.predicate.apply(event.getValue())) {
+                                abortionExceptions.add(new Exception("Abort due to "+abortCondition.source+" -> "+abortCondition.sensor));
+                                semaphore.release();
+                            }
+                        }}));
+                    Object abortValue = abortCondition.source.getAttribute(abortCondition.sensor);
+                    if (abortCondition.predicate.apply(abortValue)) {
+                        abortionExceptions.add(new Exception("Abort due to "+abortCondition.source+" -> "+abortCondition.sensor));
+                    }
+                }
+                if (abortionExceptions.size() > 0) {
+                    throw new CompoundRuntimeException("Aborted waiting for ready from "+source+" "+sensor, abortionExceptions);
+                }
+
+                CountdownTimer timer = timeout!=null ? timeout.countdownTimer() : null;
+                Duration maxPeriod = ValueResolver.PRETTY_QUICK_WAIT;
+                Duration nextPeriod = ValueResolver.REAL_QUICK_PERIOD;
+                while (true) {
+                    // check the source on initial run (could be done outside the loop) 
+                    // and also (optionally) on each iteration in case it is more recent 
+                    value = source.getAttribute(sensor);
+                    if (ready(value)) break;
+
+                    if (timer!=null) {
+                        if (timer.getDurationRemaining().isShorterThan(nextPeriod)) {
+                            nextPeriod = timer.getDurationRemaining();
+                        }
+                        if (timer.isExpired()) {
+                            if (onTimeout.isPresent()) return onTimeout.get();
+                            throw new RuntimeTimeoutException("Unsatisfied after "+Duration.sinceUtc(start));
+                        }
+                    }
+
+                    String prevBlockingDetails = current.setBlockingDetails(blockingDetails);
+                    try {
+                        if (semaphore.tryAcquire(nextPeriod.toMilliseconds(), TimeUnit.MILLISECONDS)) {
+                            // immediately release so we are available for the next check
+                            semaphore.release();
+                            // if other permits have been made available (e.g. multiple notifications) drain them all as no point running multiple times
+                            semaphore.drainPermits();
+                        }
+                    } finally {
+                        current.setBlockingDetails(prevBlockingDetails);
+                    }
+
+                    // check any subscribed values which have come in first
+                    while (true) {
+                        synchronized (publishedValues) {
+                            if (publishedValues.isEmpty()) break;
+                            value = publishedValues.pop(); 
+                        }
+                        if (ready(value)) break;
+                    }
+
+                    // if unmanaged then ignore the other abort conditions
+                    if (!ignoreUnmanaged && Entities.isNoLongerManaged(entity)) {
+                        if (onUnmanaged.isPresent()) return onUnmanaged.get();
+                        throw new NotManagedException(entity);                        
+                    }
+                    
+                    if (abortionExceptions.size() > 0) {
+                        throw new CompoundRuntimeException("Aborted waiting for ready from "+source+" "+sensor, abortionExceptions);
+                    }
+
+                    nextPeriod = nextPeriod.times(2).upperBound(maxPeriod);
+                }
+                if (LOG.isDebugEnabled()) LOG.debug("Attribute-ready for {} in entity {}", sensor, source);
+                return postProcess(value);
+            } catch (InterruptedException e) {
+                throw Exceptions.propagate(e);
+            } finally {
+                if (subscription != null) {
+                    ((EntityInternal)entity).getSubscriptionContext().unsubscribe(subscription);
+                }
+                for (SubscriptionHandle handle : abortSubscriptions) {
+                    ((EntityInternal)entity).getSubscriptionContext().unsubscribe(handle);
+                }
+            }
+        }
+    }
+    
+    /**
+     * Returns a {@link Task} which blocks until the given job returns, then returns the value of that job.
+     * 
+     * @deprecated since 0.7; code will be moved into test utilities
+     */
+    @Deprecated
+    public static <T> Task<T> whenDone(Callable<T> job) {
+        return new BasicTask<T>(MutableMap.of("tag", "whenDone", "displayName", "waiting for job"), job);
+    }
+
+    /**
+     * Returns a {@link Task} which waits for the result of first parameter, then applies the function in the second
+     * parameter to it, returning that result.
+     *
+     * Particular useful in Entity configuration where config will block until Tasks have completed,
+     * allowing for example an {@link #attributeWhenReady(Entity, AttributeSensor, Predicate)} expression to be
+     * passed in the first argument then transformed by the function in the second argument to generate
+     * the value that is used for the configuration
+     */
+    public static <U,T> Task<T> transform(final Task<U> task, final Function<U,T> transformer) {
+        return transform(MutableMap.of("displayName", "transforming "+task), task, transformer);
+    }
+ 
+    /** @see #transform(Task, Function) */
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public static <U,T> Task<T> transform(Task<U> task, Closure transformer) {
+        return transform(task, GroovyJavaMethods.functionFromClosure(transformer));
+    }
+    
+    /** @see #transform(Task, Function) */
+    @SuppressWarnings({ "rawtypes" })
+    public static <U,T> Task<T> transform(final Map flags, final TaskAdaptable<U> task, final Function<U,T> transformer) {
+        return new BasicTask<T>(flags, new Callable<T>() {
+            public T call() throws Exception {
+                if (!task.asTask().isSubmitted()) {
+                    BasicExecutionContext.getCurrentExecutionContext().submit(task);
+                } 
+                return transformer.apply(task.asTask().get());
+            }});        
+    }
+     
+    /** Returns a task which waits for multiple other tasks (submitting if necessary)
+     * and performs arbitrary computation over the List of results.
+     * @see #transform(Task, Function) but note argument order is reversed (counterintuitive) to allow for varargs */
+    public static <U,T> Task<T> transformMultiple(Function<List<U>,T> transformer, @SuppressWarnings("unchecked") TaskAdaptable<U> ...tasks) {
+        return transformMultiple(MutableMap.of("displayName", "transforming multiple"), transformer, tasks);
+    }
+
+    /** @see #transformMultiple(Function, TaskAdaptable...) */
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public static <U,T> Task<T> transformMultiple(Closure transformer, TaskAdaptable<U> ...tasks) {
+        return transformMultiple(GroovyJavaMethods.functionFromClosure(transformer), tasks);
+    }
+
+    /** @see #transformMultiple(Function, TaskAdaptable...) */
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public static <U,T> Task<T> transformMultiple(Map flags, Closure transformer, TaskAdaptable<U> ...tasks) {
+        return transformMultiple(flags, GroovyJavaMethods.functionFromClosure(transformer), tasks);
+    }
+    
+    /** @see #transformMultiple(Function, TaskAdaptable...) */
+    @SuppressWarnings({ "rawtypes" })
+    public static <U,T> Task<T> transformMultiple(Map flags, final Function<List<U>,T> transformer, @SuppressWarnings("unchecked") TaskAdaptable<U> ...tasks) {
+        return transformMultiple(flags, transformer, Arrays.asList(tasks));
+    }
+    @SuppressWarnings({ "rawtypes" })
+    public static <U,T> Task<T> transformMultiple(Map flags, final Function<List<U>,T> transformer, Collection<? extends TaskAdaptable<U>> tasks) {
+        if (tasks.size()==1) {
+            return transform(flags, Iterables.getOnlyElement(tasks), new Function<U,T>() {
+                @Override
+                @Nullable
+                public T apply(@Nullable U input) {
+                    return transformer.apply(ImmutableList.of(input));
+                }
+            });
+        }
+        return transform(flags, new ParallelTask<U>(tasks), transformer);
+    }
+
+
+    /** Method which returns a Future containing a string formatted using String.format,
+     * where the arguments can be normal objects or tasks;
+     * tasks will be waited on (submitted if necessary) and their results substituted in the call
+     * to String.format.
+     * <p>
+     * Example:
+     * <pre>
+     * {@code
+     *   setConfig(URL, DependentConfiguration.formatString("%s:%s", 
+     *           DependentConfiguration.attributeWhenReady(target, Target.HOSTNAME),
+     *           DependentConfiguration.attributeWhenReady(target, Target.PORT) ) );
+     * }
+     * </pre>
+     */
+    @SuppressWarnings("unchecked")
+    public static Task<String> formatString(final String spec, final Object ...args) {
+        List<TaskAdaptable<Object>> taskArgs = Lists.newArrayList();
+        for (Object arg: args) {
+            if (arg instanceof TaskAdaptable) taskArgs.add((TaskAdaptable<Object>)arg);
+            else if (arg instanceof TaskFactory) taskArgs.add( ((TaskFactory<TaskAdaptable<Object>>)arg).newTask() );
+        }
+            
+        return transformMultiple(
+            MutableMap.<String,String>of("displayName", "formatting '"+spec+"' with "+taskArgs.size()+" task"+(taskArgs.size()!=1?"s":"")), 
+                new Function<List<Object>, String>() {
+            @Override public String apply(List<Object> input) {
+                Iterator<?> tri = input.iterator();
+                Object[] vv = new Object[args.length];
+                int i=0;
+                for (Object arg : args) {
+                    if (arg instanceof TaskAdaptable || arg instanceof TaskFactory) vv[i] = tri.next();
+                    else if (arg instanceof DeferredSupplier) vv[i] = ((DeferredSupplier<?>) arg).get();
+                    else vv[i] = arg;
+                    i++;
+                }
+                return String.format(spec, vv);
+            }},
+            taskArgs);
+    }
+
+    /** returns a task for parallel execution returning a list of values for the given sensor for the given entity list, 
+     * optionally when the values satisfy a given readiness predicate (defaulting to groovy truth if not supplied) */
+    public static <T> Task<List<T>> listAttributesWhenReady(AttributeSensor<T> sensor, Iterable<Entity> entities) {
+        return listAttributesWhenReady(sensor, entities, GroovyJavaMethods.truthPredicate());
+    }
+    
+    public static <T> Task<List<T>> listAttributesWhenReady(AttributeSensor<T> sensor, Iterable<Entity> entities, Closure<Boolean> readiness) {
+        Predicate<Object> readinessPredicate = (readiness != null) ? GroovyJavaMethods.<Object>predicateFromClosure(readiness) : GroovyJavaMethods.truthPredicate();
+        return listAttributesWhenReady(sensor, entities, readinessPredicate);
+    }
+    
+    /** returns a task for parallel execution returning a list of values of the given sensor list on the given entity, 
+     * optionally when the values satisfy a given readiness predicate (defaulting to groovy truth if not supplied) */    
+    public static <T> Task<List<T>> listAttributesWhenReady(final AttributeSensor<T> sensor, Iterable<Entity> entities, Predicate<? super T> readiness) {
+        if (readiness == null) readiness = GroovyJavaMethods.truthPredicate();
+        return builder().attributeWhenReadyFromMultiple(entities, sensor, readiness).build();
+    }
+
+    /** @see #waitForTask(Task, Entity, String) */
+    public static <T> T waitForTask(Task<T> t, Entity context) throws InterruptedException {
+        return waitForTask(t, context, null);
+    }
+    
+    /** blocks until the given task completes, submitting if necessary, returning the result of that task;
+     * optional contextMessage is available in status if this is running in a task
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T waitForTask(Task<T> t, Entity context, String contextMessage) throws InterruptedException {
+        try {
+            return (T) Tasks.resolveValue(t, Object.class, ((EntityInternal)context).getExecutionContext(), contextMessage);
+        } catch (ExecutionException e) {
+            throw Throwables.propagate(e);
+        }
+    }
+    
+    public static class AttributeAndSensorCondition<T> {
+        protected final Entity source;
+        protected final AttributeSensor<T> sensor;
+        protected final Predicate<? super T> predicate;
+        
+        public AttributeAndSensorCondition(Entity source, AttributeSensor<T> sensor, Predicate<? super T> predicate) {
+            this.source = checkNotNull(source, "source");
+            this.sensor = checkNotNull(sensor, "sensor");
+            this.predicate = checkNotNull(predicate, "predicate");
+        }
+    }
+    
+    public static ProtoBuilder builder() {
+        return new ProtoBuilder();
+    }
+    
+    /**
+     * Builder for producing variants of attributeWhenReady.
+     */
+    @Beta
+    public static class ProtoBuilder {
+        /**
+         * Will wait for the attribute on the given entity.
+         * If that entity reports {@link Lifecycle#ON_FIRE} for its {@link Attributes#SERVICE_STATE} then it will abort. 
+         */
+        public <T2> Builder<T2,T2> attributeWhenReady(Entity source, AttributeSensor<T2> sensor) {
+            return new Builder<T2,T2>(source, sensor).abortIfOnFire();
+        }
+
+        /**
+         * Will wait for the attribute on the given entity, not aborting when it goes {@link Lifecycle#ON_FIRE}.
+         */
+        public <T2> Builder<T2,T2> attributeWhenReadyAllowingOnFire(Entity source, AttributeSensor<T2> sensor) {
+            return new Builder<T2,T2>(source, sensor);
+        }
+
+        /** Constructs a builder for task for parallel execution returning a list of values of the given sensor list on the given entity, 
+         * optionally when the values satisfy a given readiness predicate (defaulting to groovy truth if not supplied) */ 
+        @Beta
+        public <T> MultiBuilder<T, T, List<T>> attributeWhenReadyFromMultiple(Iterable<? extends Entity> sources, AttributeSensor<T> sensor) {
+            return attributeWhenReadyFromMultiple(sources, sensor, GroovyJavaMethods.truthPredicate());
+        }
+        /** As {@link #attributeWhenReadyFromMultiple(Iterable, AttributeSensor)} with an explicit readiness test. */
+        @Beta
+        public <T> MultiBuilder<T, T, List<T>> attributeWhenReadyFromMultiple(Iterable<? extends Entity> sources, AttributeSensor<T> sensor, Predicate<? super T> readiness) {
+            return new MultiBuilder<T, T, List<T>>(sources, sensor, readiness);
+        }
+    }
+
+    /**
+     * Builder for producing variants of attributeWhenReady.
+     */
+    public static class Builder<T,V> {
+        protected Entity source;
+        protected AttributeSensor<T> sensor;
+        protected Predicate<? super T> readiness;
+        protected Function<? super T, ? extends V> postProcess;
+        protected List<AttributeAndSensorCondition<?>> abortSensorConditions = Lists.newArrayList();
+        protected String blockingDetails;
+        protected Duration timeout;
+        protected Maybe<V> onTimeout;
+        protected  boolean ignoreUnmanaged = WaitInTaskForAttributeReady.DEFAULT_IGNORE_UNMANAGED;
+        protected Maybe<V> onUnmanaged;
+
+        protected Builder(Entity source, AttributeSensor<T> sensor) {
+            this.source = source;
+            this.sensor = sensor;
+        }
+        
+        /**
+         * Will wait for the attribute on the given entity.
+         * If that entity report {@link Lifecycle#ON_FIRE} for its {@link Attributes#SERVICE_STATE_ACTUAL} then it will abort.
+         * @deprecated since 0.7.0 use {@link DependentConfiguration#builder()} then {@link ProtoBuilder#attributeWhenReady(Entity, AttributeSensor)} then {@link #abortIfOnFire()} 
+         */
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        public <T2> Builder<T2,T2> attributeWhenReady(Entity source, AttributeSensor<T2> sensor) {
+            this.source = checkNotNull(source, "source");
+            this.sensor = (AttributeSensor) checkNotNull(sensor, "sensor");
+            abortIfOnFire();
+            return (Builder<T2, T2>) this;
+        }
+        public Builder<T,V> readiness(Closure<Boolean> val) {
+            this.readiness = GroovyJavaMethods.predicateFromClosure(checkNotNull(val, "val"));
+            return this;
+        }
+        public Builder<T,V> readiness(Predicate<? super T> val) {
+            this.readiness = checkNotNull(val, "ready");
+            return this;
+        }
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        public <V2> Builder<T,V2> postProcess(Closure<V2> val) {
+            this.postProcess = (Function) GroovyJavaMethods.<T,V2>functionFromClosure(checkNotNull(val, "postProcess"));
+            return (Builder<T,V2>) this;
+        }
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        public <V2> Builder<T,V2> postProcess(final Function<? super T, V2>  val) {
+            this.postProcess = (Function) checkNotNull(val, "postProcess");
+            return (Builder<T,V2>) this;
+        }
+        public <T2> Builder<T,V> abortIf(Entity source, AttributeSensor<T2> sensor) {
+            return abortIf(source, sensor, GroovyJavaMethods.truthPredicate());
+        }
+        public <T2> Builder<T,V> abortIf(Entity source, AttributeSensor<T2> sensor, Predicate<? super T2> predicate) {
+            abortSensorConditions.add(new AttributeAndSensorCondition<T2>(source, sensor, predicate));
+            return this;
+        }
+        public Builder<T,V> abortIfOnFire() {
+            abortIf(source, Attributes.SERVICE_STATE_ACTUAL, Predicates.equalTo(Lifecycle.ON_FIRE));
+            return this;
+        }
+        public Builder<T,V> blockingDetails(String val) {
+            blockingDetails = val;
+            return this;
+        }
+        /** specifies an optional timeout; by default it waits forever, or until unmanaged or other abort condition */
+        public Builder<T,V> timeout(Duration val) {
+            timeout = val;
+            return this;
+        }
+        public Builder<T,V> onTimeoutReturn(V val) {
+            onTimeout = Maybe.of(val);
+            return this;
+        }
+        public Builder<T,V> onTimeoutThrow() {
+            onTimeout = Maybe.<V>absent();
+            return this;
+        }
+        public Builder<T,V> onUnmanagedReturn(V val) {
+            onUnmanaged = Maybe.of(val);
+            return this;
+        }
+        public Builder<T,V> onUnmanagedThrow() {
+            onUnmanaged = Maybe.<V>absent();
+            return this;
+        }
+        /** @since 0.7.0 included in case old behaviour of not checking whether the entity is managed is required
+         * (I can't see why it is; polling will likely give errors, once it is unmanaged this will never completed,
+         * and before management the current code will continue, so long as there are no other errors) */ @Deprecated
+        public Builder<T,V> onUnmanagedContinue() {
+            ignoreUnmanaged = true;
+            return this;
+        }
+        /** take advantage of the fact that this builder can build multiple times, allowing subclasses 
+         * to change the source along the way */
+        protected Builder<T,V> source(Entity source) {
+            this.source = source;
+            return this;
+        }
+        /** as {@link #source(Entity)} */
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        protected Builder<T,V> sensor(AttributeSensor<? extends T> sensor) {
+            this.sensor = (AttributeSensor) sensor;
+            return this;
+        }
+        public Task<V> build() {
+            validate();
+            
+            return Tasks.<V>builder().dynamic(false)
+                .name("waiting on "+sensor.getName())
+                .description("Waiting on sensor "+sensor.getName()+" from "+source)
+                .tag("attributeWhenReady")
+                .body(new WaitInTaskForAttributeReady<T,V>(this))
+                .build();
+        }
+        
+        public V runNow() {
+            validate();
+            return new WaitInTaskForAttributeReady<T,V>(this).call();
+        }
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        private void validate() {
+            checkNotNull(source, "Entity source");
+            checkNotNull(sensor, "Sensor");
+            if (readiness == null) readiness = GroovyJavaMethods.truthPredicate();
+            if (postProcess == null) postProcess = (Function) Functions.identity();
+        }
+    }
+
+    /**
+     * Builder for producing variants of attributeWhenReady.
+     */
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Beta
+    public static class MultiBuilder<T, V, V2> {
+        protected final String name;
+        protected final String descriptionBase;
+        protected final Builder<T,V> builder;
+        // if desired, the use of this multiSource could allow different conditions; 
+        // but probably an easier API just for the caller to build the parallel task  
+        protected final List<AttributeAndSensorCondition<?>> multiSource = Lists.newArrayList();
+        protected Function<? super List<V>, V2> postProcessFromMultiple;
+        
+        /** returns a task for parallel execution returning a list of values of the given sensor list on the given entity, 
+         * optionally when the values satisfy a given readiness predicate (defaulting to groovy truth if not supplied) */ 
+        @Beta
+        protected MultiBuilder(Iterable<? extends Entity> sources, AttributeSensor<T> sensor) {
+            this(sources, sensor, GroovyJavaMethods.truthPredicate());
+        }
+        @Beta
+        protected MultiBuilder(Iterable<? extends Entity> sources, AttributeSensor<T> sensor, Predicate<? super T> readiness) {
+            builder = new Builder<T,V>(null, sensor);
+            builder.readiness(readiness);
+            
+            for (Entity s : checkNotNull(sources, "sources")) {
+                multiSource.add(new AttributeAndSensorCondition<T>(s, sensor, readiness));
+            }
+            this.name = "waiting on "+sensor.getName();
+            this.descriptionBase = "waiting on "+sensor.getName()+" "+readiness
+                +" from "+Iterables.size(sources)+" entit"+Strings.ies(sources);
+        }
+        
+        /** Apply post-processing to the entire list of results */
+        public <V2b> MultiBuilder<T, V, V2b> postProcessFromMultiple(final Function<? super List<V>, V2b> val) {
+            this.postProcessFromMultiple = (Function) checkNotNull(val, "postProcessFromMulitple");
+            return (MultiBuilder<T,V, V2b>) this;
+        }
+        /** Apply post-processing to the entire list of results 
+         * See {@link CollectionFunctionals#all(Predicate)} and {@link CollectionFunctionals#quorum(org.apache.brooklyn.util.collections.QuorumCheck, Predicate)
+         * which allow useful arguments. */
+        public MultiBuilder<T, V, Boolean> postProcessFromMultiple(final Predicate<? super List<V>> val) {
+            return postProcessFromMultiple(Functions.forPredicate(val));
+        }
+        
+        public <V1> MultiBuilder<T, V1, V2> postProcess(Closure<V1> val) {
+            builder.postProcess(val);
+            return (MultiBuilder<T, V1, V2>) this;
+        }
+        public <V1> MultiBuilder<T, V1, V2> postProcess(final Function<? super T, V1>  val) {
+            builder.postProcess(val);
+            return (MultiBuilder<T, V1, V2>) this;
+        }
+        public <T2> MultiBuilder<T, V, V2> abortIf(Entity source, AttributeSensor<T2> sensor) {
+            builder.abortIf(source, sensor);
+            return this;
+        }
+        public <T2> MultiBuilder<T, V, V2> abortIf(Entity source, AttributeSensor<T2> sensor, Predicate<? super T2> predicate) {
+            builder.abortIf(source, sensor, predicate);
+            return this;
+        }
+        public MultiBuilder<T, V, V2> abortIfOnFire() {
+            builder.abortIfOnFire();
+            return this;
+        }
+        public MultiBuilder<T, V, V2> blockingDetails(String val) {
+            builder.blockingDetails(val);
+            return this;
+        }
+        public MultiBuilder<T, V, V2> timeout(Duration val) {
+            builder.timeout(val);
+            return this;
+        }
+        public MultiBuilder<T, V, V2> onTimeoutReturn(V val) {
+            builder.onTimeoutReturn(val);
+            return this;
+        }
+        public MultiBuilder<T, V, V2> onTimeoutThrow() {
+            builder.onTimeoutThrow();
+            return this;
+        }
+        public MultiBuilder<T, V, V2> onUnmanagedReturn(V val) {
+            builder.onUnmanagedReturn(val);
+            return this;
+        }
+        public MultiBuilder<T, V, V2> onUnmanagedThrow() {
+            builder.onUnmanagedThrow();
+            return this;
+        }
+        
+        public Task<V2> build() {
+            List<Task<V>> tasks = MutableList.of();
+            for (AttributeAndSensorCondition<?> source: multiSource) {
+                builder.source(source.source);
+                builder.sensor((AttributeSensor)source.sensor);
+                builder.readiness((Predicate)source.predicate);
+                tasks.add(builder.build());
+            }
+            final Task<List<V>> parallelTask = Tasks.<List<V>>builder().parallel(true).addAll(tasks)
+                .name(name)
+                .description(descriptionBase+
+                    (builder.timeout!=null ? ", timeout "+builder.timeout : ""))
+                .build();
+            
+            if (postProcessFromMultiple == null) {
+                // V2 should be the right type in normal operations
+                return (Task<V2>) parallelTask;
+            } else {
+                return Tasks.<V2>builder().name(name).description(descriptionBase)
+                    .tag("attributeWhenReady")
+                    .body(new Callable<V2>() {
+                        @Override public V2 call() throws Exception {
+                            List<V> prePostProgress = DynamicTasks.queue(parallelTask).get();
+                            return DynamicTasks.queue(
+                                Tasks.<V2>builder().name("post-processing").description("Applying "+postProcessFromMultiple)
+                                    .body(Functionals.callable(postProcessFromMultiple, prePostProgress))
+                                    .build()).get();
+                        }
+                    })
+                    .build();
+            }
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/sensor/HttpRequestSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/HttpRequestSensor.java b/core/src/main/java/org/apache/brooklyn/core/sensor/HttpRequestSensor.java
new file mode 100644
index 0000000..79660ce
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/sensor/HttpRequestSensor.java
@@ -0,0 +1,96 @@
+/*
+ * 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.core.sensor;
+
+import java.net.URI;
+
+import net.minidev.json.JSONObject;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.AddSensor;
+import org.apache.brooklyn.sensor.feed.http.HttpFeed;
+import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
+import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Functions;
+import com.google.common.base.Supplier;
+
+/**
+ * Configurable {@link org.apache.brooklyn.api.entity.EntityInitializer} which adds an HTTP sensor feed to retrieve the
+ * {@link JSONObject} from a JSON response in order to populate the sensor with the data at the {@code jsonPath}.
+ *
+ * @see SshCommandSensor
+ * @see JmxAttributeSensor
+ */
+@Beta
+public final class HttpRequestSensor<T> extends AddSensor<T> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(HttpRequestSensor.class);
+
+    public static final ConfigKey<String> SENSOR_URI = ConfigKeys.newStringConfigKey("uri", "HTTP URI to poll for JSON");
+    public static final ConfigKey<String> JSON_PATH = ConfigKeys.newStringConfigKey("jsonPath", "JSON path to select in HTTP response; default $", "$");
+    public static final ConfigKey<String> USERNAME = ConfigKeys.newStringConfigKey("username", "Username for HTTP request, if required");
+    public static final ConfigKey<String> PASSWORD = ConfigKeys.newStringConfigKey("password", "Password for HTTP request, if required");
+
+    protected final Supplier<URI> uri;
+    protected final String jsonPath;
+    protected final String username;
+    protected final String password;
+
+    public HttpRequestSensor(final ConfigBag params) {
+        super(params);
+
+        uri = new Supplier<URI>() {
+            @Override
+            public URI get() {
+                return URI.create(params.get(SENSOR_URI));
+            }
+        };
+        jsonPath = params.get(JSON_PATH);
+        username = params.get(USERNAME);
+        password = params.get(PASSWORD);
+    }
+
+    @Override
+    public void apply(final EntityLocal entity) {
+        super.apply(entity);
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Adding HTTP JSON sensor {} to {}", name, entity);
+        }
+
+        HttpPollConfig<T> pollConfig = new HttpPollConfig<T>(sensor)
+                .checkSuccess(HttpValueFunctions.responseCodeEquals(200))
+                .onFailureOrException(Functions.constant((T) null))
+                .onSuccess(HttpValueFunctions.<T>jsonContentsFromPath(jsonPath))
+                .period(period);
+
+        HttpFeed.builder().entity(entity)
+                .baseUri(uri)
+                .credentialsIfNotNull(username, password)
+                .poll(pollConfig)
+                .build();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/sensor/PortAttributeSensorAndConfigKey.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/PortAttributeSensorAndConfigKey.java b/core/src/main/java/org/apache/brooklyn/core/sensor/PortAttributeSensorAndConfigKey.java
new file mode 100644
index 0000000..3de0de6
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/sensor/PortAttributeSensorAndConfigKey.java
@@ -0,0 +1,141 @@
+/*
+ * 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.core.sensor;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.location.MachineProvisioningLocation;
+import org.apache.brooklyn.api.location.PortRange;
+import org.apache.brooklyn.api.location.PortSupplier;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
+import org.apache.brooklyn.core.internal.BrooklynInitialization;
+import org.apache.brooklyn.core.location.Locations;
+import org.apache.brooklyn.util.core.flags.TypeCoercions;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+
+/**
+ * A {@link Sensor} describing a port on a system,
+ * with a {@link ConfigKey} which can be configured with a port range
+ * (either a number e.g. 80, or a string e.g. "80" or "8080-8089" or even "80, 8080-8089, 8800+", or a list of these).
+ * <p>
+ * To convert at runtime a single port is chosen, respecting the entity.
+ */
+public class PortAttributeSensorAndConfigKey extends AttributeSensorAndConfigKey<PortRange,Integer> {
+
+    private static final long serialVersionUID = 4680651022807491321L;
+
+    public static final Logger LOG = LoggerFactory.getLogger(PortAttributeSensorAndConfigKey.class);
+
+    static { BrooklynInitialization.initAll(); }
+
+    public PortAttributeSensorAndConfigKey(String name) {
+        this(name, name, null);
+    }
+    public PortAttributeSensorAndConfigKey(String name, String description) {
+        this(name, description, null);
+    }
+    public PortAttributeSensorAndConfigKey(String name, String description, Object defaultValue) {
+        super(PortRange.class, Integer.class, name, description, defaultValue);
+    }
+    public PortAttributeSensorAndConfigKey(PortAttributeSensorAndConfigKey orig, Object defaultValue) {
+        super(orig, TypeCoercions.coerce(defaultValue, PortRange.class));
+    }
+    @Override
+    protected Integer convertConfigToSensor(PortRange value, Entity entity) {
+        if (value==null) return null;
+        Collection<? extends Location> locations = entity.getLocations();
+        if (!locations.isEmpty()) {
+            Maybe<? extends Location> lo = Locations.findUniqueMachineLocation(locations);
+            if (!lo.isPresent()) {
+                // Try a unique location which isn't a machine provisioner
+                Iterator<? extends Location> li = Iterables.filter(locations,
+                        Predicates.not(Predicates.instanceOf(MachineProvisioningLocation.class))).iterator();
+                if (li.hasNext()) lo = Maybe.of(li.next());
+                if (li.hasNext()) lo = Maybe.absent();
+            }
+            // Fall back to selecting the single location
+            if (!lo.isPresent() && locations.size() == 1) {
+                lo = Maybe.of(locations.iterator().next());
+            }
+            if (LOG.isTraceEnabled()) {
+                LOG.trace("Convert config to sensor for {} found locations: {}. Selected: {}", new Object[] {entity, locations, lo});
+            }
+            if (lo.isPresent()) {
+                Location l = lo.get();
+                Optional<Boolean> locationRunning = Optional.fromNullable(l.getConfig(BrooklynConfigKeys.SKIP_ENTITY_START_IF_RUNNING));
+                Optional<Boolean> entityRunning = Optional.fromNullable(entity.getConfig(BrooklynConfigKeys.SKIP_ENTITY_START_IF_RUNNING));
+                Optional<Boolean> locationInstalled = Optional.fromNullable(l.getConfig(BrooklynConfigKeys.SKIP_ENTITY_INSTALLATION));
+                Optional<Boolean> entityInstalled = Optional.fromNullable(entity.getConfig(BrooklynConfigKeys.SKIP_ENTITY_INSTALLATION));
+                Optional<Boolean> entityStarted = Optional.fromNullable(entity.getConfig(BrooklynConfigKeys.SKIP_ENTITY_START));
+                boolean skipCheck = locationRunning.or(entityRunning).or(locationInstalled).or(entityInstalled).or(entityStarted).or(false);
+                if (l instanceof PortSupplier) {
+                    int p = ((PortSupplier) l).obtainPort(value);
+                    if (p != -1) {
+                        LOG.debug("{}: choosing port {} for {}", new Object[] { entity, p, getName() });
+                        return p;
+                    }
+                    // If we are not skipping install or already started, fail now
+                    if (!skipCheck) {
+                        int rangeSize = Iterables.size(value);
+                        if (rangeSize == 0) {
+                            LOG.warn("{}: no port available for {} (empty range {})", new Object[] { entity, getName(), value });
+                        } else if (rangeSize == 1) {
+                            Integer pp = value.iterator().next();
+                            if (pp > 1024) {
+                                LOG.warn("{}: port {} not available for {}", new Object[] { entity, pp, getName() });
+                            } else {
+                                LOG.warn("{}: port {} not available for {} (root may be required?)", new Object[] { entity, pp, getName() });
+                            }
+                        } else {
+                            LOG.warn("{}: no port available for {} (tried range {})", new Object[] { entity, getName(), value });
+                        }
+                        return null; // Definitively, no ports available
+                    }
+                }
+                // Ports may be available, we just can't tell from the location
+                Integer v = (value.isEmpty() ? null : value.iterator().next());
+                LOG.debug("{}: choosing port {} (unconfirmed) for {}", new Object[] { entity, v, getName() });
+                return v;
+            } else {
+                LOG.warn("{}: ports not applicable, or not yet applicable, because has multiple locations {}; ignoring ", new Object[] { entity, locations, getName() });
+            }
+        } else {
+            LOG.warn("{}: ports not applicable, or not yet applicable, bacause has no locations; ignoring {}", entity, getName());
+        }
+        return null;
+    }
+
+    @Override
+    protected Integer convertConfigToSensor(PortRange value, ManagementContext managementContext) {
+        LOG.warn("ports not applicable, because given managementContext rather than entity; ignoring {}", getName());
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/sensor/Sensors.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/Sensors.java b/core/src/main/java/org/apache/brooklyn/core/sensor/Sensors.java
new file mode 100644
index 0000000..05227d0
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/sensor/Sensors.java
@@ -0,0 +1,164 @@
+/*
+ * 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.core.sensor;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URL;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.AttributeSensor.SensorPersistenceMode;
+import org.apache.brooklyn.core.config.render.RendererHints;
+import org.apache.brooklyn.util.net.UserAndHostAndPort;
+import org.apache.brooklyn.util.text.StringFunctions;
+import org.apache.brooklyn.util.time.Duration;
+import org.apache.brooklyn.util.time.Time;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.common.net.HostAndPort;
+import com.google.common.reflect.TypeToken;
+
+public class Sensors {
+
+    @Beta
+    public static <T> Builder<T> builder(TypeToken<T> type, String name) {
+        return new Builder<T>().type(type).name(name);
+    }
+
+    @Beta
+    public static <T> Builder<T> builder(Class<T> type, String name) {
+        return new Builder<T>().type(type).name(name);
+    }
+    
+    @Beta
+    public static class Builder<T> {
+        private String name;
+        private TypeToken<T> type;
+        private String description;
+        private SensorPersistenceMode persistence;
+        
+        protected Builder() { // use builder(type, name) instead
+        }
+        public Builder<T> name(String val) {
+            this.name = checkNotNull(val, "name"); return this;
+        }
+        public Builder<T> type(Class<T> val) {
+            return type(TypeToken.of(val));
+        }
+        public Builder<T> type(TypeToken<T> val) {
+            this.type = checkNotNull(val, "type"); return this;
+        }
+        public Builder<T> description(String val) {
+            this.description = val; return this;
+        }
+        public Builder<T> persistence(SensorPersistenceMode val) {
+            this.persistence = val; return this;
+        }
+        public AttributeSensor<T> build() {
+            return new BasicAttributeSensor<T>(type, name, description, persistence);
+        }
+    }
+
+    public static <T> AttributeSensor<T> newSensor(Class<T> type, String name) {
+        return new BasicAttributeSensor<T>(type, name);
+    }
+
+    public static <T> AttributeSensor<T> newSensor(Class<T> type, String name, String description) {
+        return new BasicAttributeSensor<T>(type, name, description);
+    }
+
+    public static <T> AttributeSensor<T> newSensor(TypeToken<T> type, String name, String description) {
+        return new BasicAttributeSensor<T>(type, name, description);
+    }
+
+    public static AttributeSensor<String> newStringSensor(String name) {
+        return newSensor(String.class, name);
+    }
+
+    public static AttributeSensor<String> newStringSensor(String name, String description) {
+        return newSensor(String.class, name, description);
+    }
+
+    public static AttributeSensor<Integer> newIntegerSensor(String name) {
+        return newSensor(Integer.class, name);
+    }
+
+    public static AttributeSensor<Integer> newIntegerSensor(String name, String description) {
+        return newSensor(Integer.class, name, description);
+    }
+
+    public static AttributeSensor<Long> newLongSensor(String name) {
+        return newSensor(Long.class, name);
+    }
+
+    public static AttributeSensor<Long> newLongSensor(String name, String description) {
+        return newSensor(Long.class, name, description);
+    }
+
+    public static AttributeSensor<Double> newDoubleSensor(String name) {
+        return newSensor(Double.class, name);
+    }
+
+    public static AttributeSensor<Double> newDoubleSensor(String name, String description) {
+        return newSensor(Double.class, name, description);
+    }
+
+    public static AttributeSensor<Boolean> newBooleanSensor(String name) {
+        return newSensor(Boolean.class, name);
+    }
+
+    public static AttributeSensor<Boolean> newBooleanSensor(String name, String description) {
+        return newSensor(Boolean.class, name, description);
+    }
+
+    // Extensions to sensors
+
+    public static <T> AttributeSensor<T> newSensorRenamed(String newName, AttributeSensor<T> sensor) {
+        return new BasicAttributeSensor<T>(sensor.getTypeToken(), newName, sensor.getDescription());
+    }
+
+    public static <T> AttributeSensor<T> newSensorWithPrefix(String prefix, AttributeSensor<T> sensor) {
+        return newSensorRenamed(prefix+sensor.getName(), sensor);
+    }
+
+    // Display hints for common utility objects
+
+    static {
+        RendererHints.register(Duration.class, RendererHints.displayValue(Time.fromDurationToTimeStringRounded()));
+        RendererHints.register(HostAndPort.class, RendererHints.displayValue(StringFunctions.toStringFunction()));
+        RendererHints.register(UserAndHostAndPort.class, RendererHints.displayValue(StringFunctions.toStringFunction()));
+        RendererHints.register(InetAddress.class, RendererHints.displayValue(new Function<InetAddress,String>() {
+            @Override
+            public String apply(@Nullable InetAddress input) {
+                return input == null ? null : input.getHostAddress();
+            }
+        }));
+
+        RendererHints.register(URL.class, RendererHints.displayValue(StringFunctions.toStringFunction()));
+        RendererHints.register(URL.class, RendererHints.openWithUrl(StringFunctions.toStringFunction()));
+        RendererHints.register(URI.class, RendererHints.displayValue(StringFunctions.toStringFunction()));
+        RendererHints.register(URI.class, RendererHints.openWithUrl(StringFunctions.toStringFunction()));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/sensor/StaticSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/StaticSensor.java b/core/src/main/java/org/apache/brooklyn/core/sensor/StaticSensor.java
new file mode 100644
index 0000000..4a7b1d4
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/sensor/StaticSensor.java
@@ -0,0 +1,72 @@
+/*
+ * 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.core.sensor;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.AddSensor;
+import org.apache.brooklyn.sensor.enricher.Propagator;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.core.task.Tasks;
+import org.apache.brooklyn.util.core.task.ValueResolver;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Supplier;
+
+/** 
+ * Provides an initializer/feed which simply sets a given value.
+ * <p>
+ * {@link Task}/{@link Supplier} values are resolved when written,
+ * unlike config values which are resolved on each read.
+ * <p>
+ * This supports a {@link StaticSensor#SENSOR_PERIOD} 
+ * which can be useful if the supplied value is such a function.
+ * However when the source is another sensor,
+ * consider using {@link Propagator} which listens for changes instead. */
+public class StaticSensor<T> extends AddSensor<T> {
+
+    private static final Logger log = LoggerFactory.getLogger(StaticSensor.class);
+    
+    public static final ConfigKey<Object> STATIC_VALUE = ConfigKeys.newConfigKey(Object.class, "static.value");
+
+    private final Object value;
+
+    public StaticSensor(ConfigBag params) {
+        super(params);
+        value = params.get(STATIC_VALUE);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void apply(EntityLocal entity) {
+        super.apply(entity);
+        
+        Maybe<T> v = Tasks.resolving(value).as((Class<T>)sensor.getType()).timeout(ValueResolver.PRETTY_QUICK_WAIT).getMaybe();
+        if (v.isPresent()) {
+            log.debug(this+" setting sensor "+sensor+" to "+v.get());
+            entity.setAttribute(sensor, v.get());
+        } else {
+            log.debug(this+" not setting sensor "+sensor+"; cannot resolve "+value);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/sensor/TemplatedStringAttributeSensorAndConfigKey.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/TemplatedStringAttributeSensorAndConfigKey.java b/core/src/main/java/org/apache/brooklyn/core/sensor/TemplatedStringAttributeSensorAndConfigKey.java
new file mode 100644
index 0000000..953b7d8
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/sensor/TemplatedStringAttributeSensorAndConfigKey.java
@@ -0,0 +1,66 @@
+/*
+ * 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.core.sensor;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
+import org.apache.brooklyn.util.core.text.TemplateProcessor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * A {@link ConfigKey} which takes a freemarker-templated string,
+ * and whose value is converted to a sensor by processing the template 
+ * with access to config and methods on the entity where it is set.
+ */
+public class TemplatedStringAttributeSensorAndConfigKey extends BasicAttributeSensorAndConfigKey<String> {
+    private static final long serialVersionUID = 4680651022807491321L;
+    
+    public static final Logger LOG = LoggerFactory.getLogger(TemplatedStringAttributeSensorAndConfigKey.class);
+
+    public TemplatedStringAttributeSensorAndConfigKey(String name) {
+        this(name, name, null);
+    }
+    public TemplatedStringAttributeSensorAndConfigKey(String name, String description) {
+        this(name, description, null);
+    }
+    public TemplatedStringAttributeSensorAndConfigKey(String name, String description, String defaultValue) {
+        super(String.class, name, description, defaultValue);
+    }
+    public TemplatedStringAttributeSensorAndConfigKey(TemplatedStringAttributeSensorAndConfigKey orig, String defaultValue) {
+        super(orig, defaultValue);
+    }
+    
+    @Override
+    protected String convertConfigToSensor(String value, Entity entity) {
+        if (value == null) return null;
+        return TemplateProcessor.processTemplateContents(value, (EntityInternal)entity, ImmutableMap.<String,Object>of());
+    }
+    
+    @Override
+    protected String convertConfigToSensor(String value, ManagementContext managementContext) {
+        if (value == null) return null;
+        return TemplateProcessor.processTemplateContents(value, (ManagementContextInternal)managementContext, ImmutableMap.<String,Object>of());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/server/entity/BrooklynMetrics.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/server/entity/BrooklynMetrics.java b/core/src/main/java/org/apache/brooklyn/core/server/entity/BrooklynMetrics.java
index 5f060c2..6e9cef5 100644
--- a/core/src/main/java/org/apache/brooklyn/core/server/entity/BrooklynMetrics.java
+++ b/core/src/main/java/org/apache/brooklyn/core/server/entity/BrooklynMetrics.java
@@ -21,8 +21,8 @@ package org.apache.brooklyn.core.server.entity;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 @ImplementedBy(BrooklynMetricsImpl.class)

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/entity/group/AbstractGroup.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/AbstractGroup.java b/core/src/main/java/org/apache/brooklyn/entity/group/AbstractGroup.java
index 00710ca..aa9ca90 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/AbstractGroup.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/AbstractGroup.java
@@ -27,7 +27,7 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ComputeServiceIndicatorsFromChildrenAndMembers;
 import org.apache.brooklyn.core.entity.trait.Changeable;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.util.collections.QuorumCheck;
 import org.apache.brooklyn.util.collections.QuorumCheck.QuorumChecks;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/entity/group/DynamicCluster.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicCluster.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicCluster.java
index bf39663..b6ee23a 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicCluster.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicCluster.java
@@ -38,11 +38,11 @@ import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.factory.EntityFactory;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.trait.MemberReplaceable;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.group.zoneaware.BalancingNodePlacementStrategy;
 import org.apache.brooklyn.entity.group.zoneaware.ProportionalZoneFailureDetector;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
-import org.apache.brooklyn.sensor.core.BasicNotificationSensor;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabric.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabric.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabric.java
index fc53c21..943ed9b 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabric.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabric.java
@@ -28,7 +28,7 @@ import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.factory.EntityFactory;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 import com.google.common.collect.ImmutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/entity/group/DynamicGroup.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicGroup.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicGroup.java
index bb43d3b..c06aa58 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicGroup.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicGroup.java
@@ -30,7 +30,7 @@ import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 import com.google.common.base.Predicate;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/entity/group/DynamicMultiGroup.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicMultiGroup.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicMultiGroup.java
index 5e9b75f..048a304 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicMultiGroup.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicMultiGroup.java
@@ -27,7 +27,7 @@ import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 import com.google.common.annotations.Beta;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/entity/stock/DelegateEntity.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/stock/DelegateEntity.java b/core/src/main/java/org/apache/brooklyn/entity/stock/DelegateEntity.java
index 645426a..793bac6 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/stock/DelegateEntity.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/stock/DelegateEntity.java
@@ -26,8 +26,8 @@ import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.config.render.RendererHints;
-import org.apache.brooklyn.sensor.core.AttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 
 import com.google.common.base.Function;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/location/winrm/AdvertiseWinrmLoginPolicy.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/winrm/AdvertiseWinrmLoginPolicy.java b/core/src/main/java/org/apache/brooklyn/location/winrm/AdvertiseWinrmLoginPolicy.java
index 0d5828d..0945407 100644
--- a/core/src/main/java/org/apache/brooklyn/location/winrm/AdvertiseWinrmLoginPolicy.java
+++ b/core/src/main/java/org/apache/brooklyn/location/winrm/AdvertiseWinrmLoginPolicy.java
@@ -26,9 +26,9 @@ import org.apache.brooklyn.api.sensor.SensorEvent;
 import org.apache.brooklyn.api.sensor.SensorEventListener;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.policy.AbstractPolicy;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.apache.brooklyn.sensor.core.Sensors;
 
 import com.google.common.annotations.Beta;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/core/AttributeMap.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/AttributeMap.java b/core/src/main/java/org/apache/brooklyn/sensor/core/AttributeMap.java
deleted file mode 100644
index 4125a96..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/core/AttributeMap.java
+++ /dev/null
@@ -1,202 +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.core;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.Map;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.core.BrooklynLogging;
-import org.apache.brooklyn.core.entity.AbstractEntity;
-import org.apache.brooklyn.util.core.flags.TypeCoercions;
-import org.apache.brooklyn.util.guava.Maybe;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.base.Objects;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-
-/**
- * A {@link Map} of {@link Entity} attribute values.
- */
-public final class AttributeMap implements Serializable {
-
-    private static final long serialVersionUID = -6834883734250888344L;
-
-    static final Logger log = LoggerFactory.getLogger(AttributeMap.class);
-
-    private static enum Marker {
-        NULL;
-    }
-    
-    private final AbstractEntity entity;
-
-    // Assumed to be something like a ConcurrentMap passed in.
-    private final Map<Collection<String>, Object> values;
-
-    /**
-     * Creates a new AttributeMap.
-     *
-     * @param entity the EntityLocal this AttributeMap belongs to.
-     * @throws IllegalArgumentException if entity is null
-     */
-    public AttributeMap(AbstractEntity entity, Map<Collection<String>, Object> storage) {
-        this.entity = checkNotNull(entity, "entity must be specified");
-        this.values = checkNotNull(storage, "storage map must not be null");
-    }
-
-    public Map<Collection<String>, Object> asRawMap() {
-        return ImmutableMap.copyOf(values);
-    }
-
-    public Map<String, Object> asMap() {
-        Map<String, Object> result = Maps.newLinkedHashMap();
-        for (Map.Entry<Collection<String>, Object> entry : values.entrySet()) {
-            String sensorName = Joiner.on('.').join(entry.getKey());
-            Object val = (isNull(entry.getValue())) ? null : entry.getValue();
-            result.put(sensorName, val);
-        }
-        return result;
-    }
-    
-    /**
-     * Updates the value.
-     *
-     * @param path the path to the value.
-     * @param newValue the new value
-     * @return the old value.
-     * @throws IllegalArgumentException if path is null or empty
-     */
-    // TODO path must be ordered(and legal to contain duplicates like "a.b.a"; list would be better
-    public <T> T update(Collection<String> path, T newValue) {
-        checkPath(path);
-
-        if (newValue == null) {
-            newValue = typedNull();
-        }
-
-        if (log.isTraceEnabled()) {
-            log.trace("setting sensor {}={} for {}", new Object[] {path, newValue, entity});
-        }
-
-        @SuppressWarnings("unchecked")
-        T oldValue = (T) values.put(path, newValue);
-        return (isNull(oldValue)) ? null : oldValue;
-    }
-
-    private void checkPath(Collection<String> path) {
-        Preconditions.checkNotNull(path, "path can't be null");
-        Preconditions.checkArgument(!path.isEmpty(), "path can't be empty");
-    }
-
-    public <T> T update(AttributeSensor<T> attribute, T newValue) {
-        T oldValue = updateWithoutPublishing(attribute, newValue);
-        entity.emitInternal(attribute, newValue);
-        return oldValue;
-    }
-    
-    public <T> T updateWithoutPublishing(AttributeSensor<T> attribute, T newValue) {
-        if (log.isTraceEnabled()) {
-            Object oldValue = getValue(attribute);
-            if (!Objects.equal(oldValue, newValue != null)) {
-                log.trace("setting attribute {} to {} (was {}) on {}", new Object[] {attribute.getName(), newValue, oldValue, entity});
-            } else {
-                log.trace("setting attribute {} to {} (unchanged) on {}", new Object[] {attribute.getName(), newValue, this});
-            }
-        }
-
-        T oldValue = (T) update(attribute.getNameParts(), newValue);
-        
-        return (isNull(oldValue)) ? null : oldValue;
-    }
-
-    /**
-     * Where atomicity is desired, the methods in this class synchronize on the {@link #values} map.
-     */
-    public <T> T modify(AttributeSensor<T> attribute, Function<? super T, Maybe<T>> modifier) {
-        synchronized (values) {
-            T oldValue = getValue(attribute);
-            Maybe<? extends T> newValue = modifier.apply(oldValue);
-
-            if (newValue.isPresent()) {
-                if (log.isTraceEnabled()) log.trace("modified attribute {} to {} (was {}) on {}", new Object[] {attribute.getName(), newValue, oldValue, entity});
-                return update(attribute, newValue.get());
-            } else {
-                if (log.isTraceEnabled()) log.trace("modified attribute {} unchanged; not emitting on {}", new Object[] {attribute.getName(), newValue, this});
-                return oldValue;
-            }
-        }
-    }
-
-    public void remove(AttributeSensor<?> attribute) {
-        BrooklynLogging.log(log, BrooklynLogging.levelDebugOrTraceIfReadOnly(entity),
-            "removing attribute {} on {}", attribute.getName(), entity);
-
-        remove(attribute.getNameParts());
-    }
-
-    // TODO path must be ordered(and legal to contain duplicates like "a.b.a"; list would be better
-    public void remove(Collection<String> path) {
-        checkPath(path);
-
-        if (log.isTraceEnabled()) {
-            log.trace("removing sensor {} for {}", new Object[] {path, entity});
-        }
-
-        values.remove(path);
-    }
-
-    /**
-     * Gets the value
-     *
-     * @param path the path of the value to get
-     * @return the value
-     * @throws IllegalArgumentException path is null or empty.
-     */
-    public Object getValue(Collection<String> path) {
-        // TODO previously this would return a map of the sub-tree if the path matched a prefix of a group of sensors, 
-        // or the leaf value if only one value. Arguably that is not required - what is/was the use-case?
-        // 
-        checkPath(path);
-        Object result = values.get(path);
-        return (isNull(result)) ? null : result;
-    }
-
-    @SuppressWarnings("unchecked")
-    public <T> T getValue(AttributeSensor<T> sensor) {
-        return (T) TypeCoercions.coerce(getValue(sensor.getNameParts()), sensor.getType());
-    }
-
-    @SuppressWarnings("unchecked")
-    private <T> T typedNull() {
-        return (T) Marker.NULL;
-    }
-    
-    private boolean isNull(Object t) {
-        return t == Marker.NULL;
-    }
-}


[25/36] incubator-brooklyn git commit: Rename o.a.b.sensor.feed to o.a.b.feed and o.a.b.core.feed

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/feed/windows/WindowsPerformanceCounterFeed.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/feed/windows/WindowsPerformanceCounterFeed.java b/core/src/main/java/org/apache/brooklyn/feed/windows/WindowsPerformanceCounterFeed.java
new file mode 100644
index 0000000..d34d0a5
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/feed/windows/WindowsPerformanceCounterFeed.java
@@ -0,0 +1,412 @@
+/*
+ * 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.feed.windows;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import io.cloudsoft.winrm4j.winrm.WinRmToolResponse;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.mgmt.ExecutionContext;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.EffectorTasks;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.feed.AbstractFeed;
+import org.apache.brooklyn.core.feed.PollHandler;
+import org.apache.brooklyn.core.feed.Poller;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
+import org.apache.brooklyn.util.core.flags.TypeCoercions;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.time.Duration;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.common.reflect.TypeToken;
+
+/**
+ * A sensor feed that retrieves performance counters from a Windows host and posts the values to sensors.
+ *
+ * <p>To use this feed, you must provide the entity, and a collection of mappings between Windows performance counter
+ * names and Brooklyn attribute sensors.</p>
+ *
+ * <p>This feed uses SSH to invoke the windows utility <tt>typeperf</tt> to query for a specific set of performance
+ * counters, by name. The values are extracted from the response, and published to the entity's sensors.</p>
+ *
+ * <p>Example:</p>
+ *
+ * {@code
+ * @Override
+ * protected void connectSensors() {
+ *     WindowsPerformanceCounterFeed feed = WindowsPerformanceCounterFeed.builder()
+ *         .entity(entity)
+ *         .addSensor("\\Processor(_total)\\% Idle Time", CPU_IDLE_TIME)
+ *         .addSensor("\\Memory\\Available MBytes", AVAILABLE_MEMORY)
+ *         .build();
+ * }
+ * }
+ *
+ * @since 0.6.0
+ * @author richardcloudsoft
+ */
+public class WindowsPerformanceCounterFeed extends AbstractFeed {
+
+    private static final Logger log = LoggerFactory.getLogger(WindowsPerformanceCounterFeed.class);
+
+    // This pattern matches CSV line(s) with the date in the first field, and at least one further field.
+    protected static final Pattern lineWithPerfData = Pattern.compile("^\"[\\d:/\\-. ]+\",\".*\"$", Pattern.MULTILINE);
+    private static final Joiner JOINER_ON_SPACE = Joiner.on(' ');
+    private static final Joiner JOINER_ON_COMMA = Joiner.on(',');
+    private static final int OUTPUT_COLUMN_WIDTH = 100;
+
+    @SuppressWarnings("serial")
+    public static final ConfigKey<Collection<WindowsPerformanceCounterPollConfig<?>>> POLLS = ConfigKeys.newConfigKey(
+            new TypeToken<Collection<WindowsPerformanceCounterPollConfig<?>>>() {},
+            "polls");
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    public static class Builder {
+        private EntityLocal entity;
+        private Set<WindowsPerformanceCounterPollConfig<?>> polls = Sets.newLinkedHashSet();
+        private Duration period = Duration.of(30, TimeUnit.SECONDS);
+        private String uniqueTag;
+        private volatile boolean built;
+
+        public Builder entity(EntityLocal val) {
+            this.entity = checkNotNull(val, "entity");
+            return this;
+        }
+        public Builder addSensor(WindowsPerformanceCounterPollConfig<?> config) {
+            polls.add(config);
+            return this;
+        }
+        public Builder addSensor(String performanceCounterName, AttributeSensor<?> sensor) {
+            return addSensor(new WindowsPerformanceCounterPollConfig(sensor).performanceCounterName(checkNotNull(performanceCounterName, "performanceCounterName")));
+        }
+        public Builder addSensors(Map<String, AttributeSensor> sensors) {
+            for (Map.Entry<String, AttributeSensor> entry : sensors.entrySet()) {
+                addSensor(entry.getKey(), entry.getValue());
+            }
+            return this;
+        }
+        public Builder period(Duration period) {
+            this.period = checkNotNull(period, "period");
+            return this;
+        }
+        public Builder period(long millis) {
+            return period(millis, TimeUnit.MILLISECONDS);
+        }
+        public Builder period(long val, TimeUnit units) {
+            return period(Duration.of(val, units));
+        }
+        public Builder uniqueTag(String uniqueTag) {
+            this.uniqueTag = uniqueTag;
+            return this;
+        }
+        public WindowsPerformanceCounterFeed build() {
+            built = true;
+            WindowsPerformanceCounterFeed result = new WindowsPerformanceCounterFeed(this);
+            result.setEntity(checkNotNull(entity, "entity"));
+            result.start();
+            return result;
+        }
+        @Override
+        protected void finalize() {
+            if (!built) log.warn("WindowsPerformanceCounterFeed.Builder created, but build() never called");
+        }
+    }
+
+    /**
+     * For rebind; do not call directly; use builder
+     */
+    public WindowsPerformanceCounterFeed() {
+    }
+
+    protected WindowsPerformanceCounterFeed(Builder builder) {
+        List<WindowsPerformanceCounterPollConfig<?>> polls = Lists.newArrayList();
+        for (WindowsPerformanceCounterPollConfig<?> config : builder.polls) {
+            if (!config.isEnabled()) continue;
+            @SuppressWarnings({ "unchecked", "rawtypes" })
+            WindowsPerformanceCounterPollConfig<?> configCopy = new WindowsPerformanceCounterPollConfig(config);
+            if (configCopy.getPeriod() < 0) configCopy.period(builder.period);
+            polls.add(configCopy);
+        }
+        config().set(POLLS, polls);
+        initUniqueTag(builder.uniqueTag, polls);
+    }
+
+    @Override
+    protected void preStart() {
+        Collection<WindowsPerformanceCounterPollConfig<?>> polls = getConfig(POLLS);
+        
+        long minPeriod = Integer.MAX_VALUE;
+        List<String> performanceCounterNames = Lists.newArrayList();
+        for (WindowsPerformanceCounterPollConfig<?> config : polls) {
+            minPeriod = Math.min(minPeriod, config.getPeriod());
+            performanceCounterNames.add(config.getPerformanceCounterName());
+        }
+        
+        Iterable<String> allParams = ImmutableList.<String>builder()
+                .add("(Get-Counter")
+                .add("-Counter")
+                .add(JOINER_ON_COMMA.join(Iterables.transform(performanceCounterNames, QuoteStringFunction.INSTANCE)))
+                .add("-SampleInterval")
+                .add("2") // TODO: extract SampleInterval as a config key
+                .add(").CounterSamples")
+                .add("|")
+                .add("Format-Table")
+                .add(String.format("@{Expression={$_.Path};width=%d},@{Expression={$_.CookedValue};width=%<d}", OUTPUT_COLUMN_WIDTH))
+                .add("-HideTableHeaders")
+                .add("|")
+                .add("Out-String")
+                .add("-Width")
+                .add(String.valueOf(OUTPUT_COLUMN_WIDTH * 2))
+                .build();
+        String command = JOINER_ON_SPACE.join(allParams);
+        log.debug("Windows performance counter poll command for {} will be: {}", entity, command);
+
+        GetPerformanceCountersJob<WinRmToolResponse> job = new GetPerformanceCountersJob(getEntity(), command);
+        getPoller().scheduleAtFixedRate(
+                new CallInEntityExecutionContext(entity, job),
+                new SendPerfCountersToSensors(getEntity(), polls),
+                minPeriod);
+    }
+
+    private static class GetPerformanceCountersJob<T> implements Callable<T> {
+
+        private final Entity entity;
+        private final String command;
+
+        GetPerformanceCountersJob(Entity entity, String command) {
+            this.entity = entity;
+            this.command = command;
+        }
+
+        @Override
+        public T call() throws Exception {
+            WinRmMachineLocation machine = EffectorTasks.getWinRmMachine(entity);
+            WinRmToolResponse response = machine.executePsScript(command);
+            return (T)response;
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    protected Poller<WinRmToolResponse> getPoller() {
+        return (Poller<WinRmToolResponse>) super.getPoller();
+    }
+
+    /**
+     * A {@link java.util.concurrent.Callable} that wraps another {@link java.util.concurrent.Callable}, where the
+     * inner {@link java.util.concurrent.Callable} is executed in the context of a
+     * specific entity.
+     *
+     * @param <T> The type of the {@link java.util.concurrent.Callable}.
+     */
+    private static class CallInEntityExecutionContext<T> implements Callable<T> {
+        private final Callable<T> job;
+        private EntityLocal entity;
+
+        private CallInEntityExecutionContext(EntityLocal entity, Callable<T> job) {
+            this.job = job;
+            this.entity = entity;
+        }
+
+        @Override
+        public T call() throws Exception {
+            ExecutionContext executionContext = ((EntityInternal) entity).getManagementSupport().getExecutionContext();
+            return executionContext.submit(Maps.newHashMap(), job).get();
+        }
+    }
+
+    @VisibleForTesting
+    static class SendPerfCountersToSensors implements PollHandler<WinRmToolResponse> {
+        private final EntityLocal entity;
+        private final List<WindowsPerformanceCounterPollConfig<?>> polls;
+        private final Set<AttributeSensor<?>> failedAttributes = Sets.newLinkedHashSet();
+        private static final Pattern MACHINE_NAME_LOOKBACK_PATTERN = Pattern.compile(String.format("(?<=\\\\\\\\.{0,%d})\\\\.*", OUTPUT_COLUMN_WIDTH));
+        
+        public SendPerfCountersToSensors(EntityLocal entity, Collection<WindowsPerformanceCounterPollConfig<?>> polls) {
+            this.entity = entity;
+            this.polls = ImmutableList.copyOf(polls);
+        }
+
+        @Override
+        public boolean checkSuccess(WinRmToolResponse val) {
+            // TODO not just using statusCode; also looking at absence of stderr.
+            // Status code is (empirically) unreliable: it returns 0 sometimes even when failed 
+            // (but never returns non-zero on success).
+            if (val.getStatusCode() != 0) return false;
+            String stderr = val.getStdErr();
+            if (stderr == null || stderr.length() != 0) return false;
+            String out = val.getStdOut();
+            if (out == null || out.length() == 0) return false;
+            return true;
+        }
+
+        @Override
+        public void onSuccess(WinRmToolResponse val) {
+            for (String pollResponse : val.getStdOut().split("\r\n")) {
+                if (Strings.isNullOrEmpty(pollResponse)) {
+                    continue;
+                }
+                String path = pollResponse.substring(0, OUTPUT_COLUMN_WIDTH - 1);
+                // The performance counter output prepends the sensor name with "\\<machinename>" so we need to remove it
+                Matcher machineNameLookbackMatcher = MACHINE_NAME_LOOKBACK_PATTERN.matcher(path);
+                if (!machineNameLookbackMatcher.find()) {
+                    continue;
+                }
+                String name = machineNameLookbackMatcher.group(0).trim();
+                String rawValue = pollResponse.substring(OUTPUT_COLUMN_WIDTH).replaceAll("^\\s+", "");
+                WindowsPerformanceCounterPollConfig<?> config = getPollConfig(name);
+                Class<?> clazz = config.getSensor().getType();
+                AttributeSensor<Object> attribute = (AttributeSensor<Object>) Sensors.newSensor(clazz, config.getSensor().getName(), config.getDescription());
+                try {
+                    Object value = TypeCoercions.coerce(rawValue, TypeToken.of(clazz));
+                    entity.setAttribute(attribute, value);
+                } catch (Exception e) {
+                    Exceptions.propagateIfFatal(e);
+                    if (failedAttributes.add(attribute)) {
+                        log.warn("Failed to coerce value '{}' to {} for {} -> {}", new Object[] {rawValue, clazz, entity, attribute});
+                    } else {
+                        if (log.isTraceEnabled()) log.trace("Failed (repeatedly) to coerce value '{}' to {} for {} -> {}", new Object[] {rawValue, clazz, entity, attribute});
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void onFailure(WinRmToolResponse val) {
+            log.error("Windows Performance Counter query did not respond as expected. exitcode={} stdout={} stderr={}",
+                    new Object[]{val.getStatusCode(), val.getStdOut(), val.getStdErr()});
+            for (WindowsPerformanceCounterPollConfig<?> config : polls) {
+                Class<?> clazz = config.getSensor().getType();
+                AttributeSensor<?> attribute = Sensors.newSensor(clazz, config.getSensor().getName(), config.getDescription());
+                entity.setAttribute(attribute, null);
+            }
+        }
+
+        @Override
+        public void onException(Exception exception) {
+            log.error("Detected exception while retrieving Windows Performance Counters from entity " +
+                    entity.getDisplayName(), exception);
+            for (WindowsPerformanceCounterPollConfig<?> config : polls) {
+                entity.setAttribute(Sensors.newSensor(config.getSensor().getClass(), config.getPerformanceCounterName(), config.getDescription()), null);
+            }
+        }
+
+        @Override
+        public String getDescription() {
+            return "" + polls;
+        }
+
+        @Override
+        public String toString() {
+            return super.toString()+"["+getDescription()+"]";
+        }
+
+        private WindowsPerformanceCounterPollConfig<?> getPollConfig(String sensorName) {
+            for (WindowsPerformanceCounterPollConfig<?> poll : polls) {
+                if (poll.getPerformanceCounterName().equalsIgnoreCase(sensorName)) {
+                    return poll;
+                }
+            }
+            throw new IllegalStateException(String.format("%s not found in configured polls: %s", sensorName, polls));
+        }
+    }
+
+    static class PerfCounterValueIterator implements Iterator<String> {
+
+        // This pattern matches the contents of the first field, and optionally matches the rest of the line as
+        // further fields. Feed the second match back into the pattern again to get the next field, and repeat until
+        // all fields are discovered.
+        protected static final Pattern splitPerfData = Pattern.compile("^\"([^\\\"]*)\"((,\"[^\\\"]*\")*)$");
+
+        private Matcher matcher;
+
+        public PerfCounterValueIterator(String input) {
+            matcher = splitPerfData.matcher(input);
+            // Throw away the first element (the timestamp) (and also confirm that we have a pattern match)
+            checkArgument(hasNext(), "input "+input+" does not match expected pattern "+splitPerfData.pattern());
+            next();
+        }
+
+        @Override
+        public boolean hasNext() {
+            return matcher != null && matcher.find();
+        }
+
+        @Override
+        public String next() {
+            String next = matcher.group(1);
+
+            String remainder = matcher.group(2);
+            if (!Strings.isNullOrEmpty(remainder)) {
+                assert remainder.startsWith(",");
+                remainder = remainder.substring(1);
+                matcher = splitPerfData.matcher(remainder);
+            } else {
+                matcher = null;
+            }
+
+            return next;
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    private static enum QuoteStringFunction implements Function<String, String> {
+        INSTANCE;
+
+        @Nullable
+        @Override
+        public String apply(@Nullable String input) {
+            return input != null ? "\"" + input + "\"" : null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/feed/windows/WindowsPerformanceCounterPollConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/feed/windows/WindowsPerformanceCounterPollConfig.java b/core/src/main/java/org/apache/brooklyn/feed/windows/WindowsPerformanceCounterPollConfig.java
new file mode 100644
index 0000000..1391c3e
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/feed/windows/WindowsPerformanceCounterPollConfig.java
@@ -0,0 +1,53 @@
+/*
+ * 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.feed.windows;
+
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.feed.PollConfig;
+
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+
+public class WindowsPerformanceCounterPollConfig<T> extends PollConfig<Object, T, WindowsPerformanceCounterPollConfig<T>>{
+
+    private String performanceCounterName;
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public WindowsPerformanceCounterPollConfig(AttributeSensor<T> sensor) {
+        super(sensor);
+        description(sensor.getDescription());
+        onSuccess((Function)Functions.identity());
+    }
+
+    public WindowsPerformanceCounterPollConfig(WindowsPerformanceCounterPollConfig<T> other) {
+        super(other);
+        this.performanceCounterName = other.performanceCounterName;
+    }
+
+    public String getPerformanceCounterName() {
+        return performanceCounterName;
+    }
+    
+    public WindowsPerformanceCounterPollConfig<T> performanceCounterName(String val) {
+        this.performanceCounterName = val; return this;
+    }
+
+    @Override protected String toStringPollSource() { return performanceCounterName; }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/AbstractFeed.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/AbstractFeed.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/AbstractFeed.java
deleted file mode 100644
index 327181a..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/AbstractFeed.java
+++ /dev/null
@@ -1,240 +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.feed;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.Collection;
-
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.mgmt.rebind.RebindSupport;
-import org.apache.brooklyn.api.mgmt.rebind.mementos.FeedMemento;
-import org.apache.brooklyn.api.sensor.Feed;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.BrooklynFeatureEnablement;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.core.mgmt.rebind.BasicFeedRebindSupport;
-import org.apache.brooklyn.core.objs.AbstractEntityAdjunct;
-import org.apache.brooklyn.util.javalang.JavaClassNames;
-import org.apache.brooklyn.util.text.Strings;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/** 
- * Captures common fields and processes for sensor feeds.
- * These generally poll or subscribe to get sensor values for an entity.
- * They make it easy to poll over http, jmx, etc.
- */
-public abstract class AbstractFeed extends AbstractEntityAdjunct implements Feed {
-
-    private static final Logger log = LoggerFactory.getLogger(AbstractFeed.class);
-
-    public static final ConfigKey<Boolean> ONLY_IF_SERVICE_UP = ConfigKeys.newBooleanConfigKey("feed.onlyIfServiceUp", "", false);
-    
-    private final Object pollerStateMutex = new Object();
-    private transient volatile Poller<?> poller;
-    private transient volatile boolean activated;
-    private transient volatile boolean suspended;
-
-    public AbstractFeed() {
-    }
-    
-    /**
-     * @deprecated since 0.7.0; use no-arg constructor; call {@link #setEntity(EntityLocal)}
-     */
-    @Deprecated
-    public AbstractFeed(EntityLocal entity) {
-        this(entity, false);
-    }
-    
-    /**
-     * @deprecated since 0.7.0; use no-arg constructor; call {@link #setEntity(EntityLocal)} and {@code setConfig(ONLY_IF_SERVICE_UP, onlyIfServiceUp)}
-     */
-    @Deprecated
-    public AbstractFeed(EntityLocal entity, boolean onlyIfServiceUp) {
-        this.entity = checkNotNull(entity, "entity");
-        setConfig(ONLY_IF_SERVICE_UP, onlyIfServiceUp);
-    }
-
-    // Ensure idempotent, as called in builders (in case not registered with entity), and also called
-    // when registering with entity
-    @Override
-    public void setEntity(EntityLocal entity) {
-        super.setEntity(entity);
-        if (BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_FEED_REGISTRATION_PROPERTY)) {
-            ((EntityInternal)entity).feeds().addFeed(this);
-        }
-    }
-
-    protected void initUniqueTag(String uniqueTag, Object ...valsForDefault) {
-        if (Strings.isNonBlank(uniqueTag)) this.uniqueTag = uniqueTag;
-        else this.uniqueTag = getDefaultUniqueTag(valsForDefault);
-    }
-
-    protected String getDefaultUniqueTag(Object ...valsForDefault) {
-        StringBuilder sb = new StringBuilder();
-        sb.append(JavaClassNames.simpleClassName(this));
-        if (valsForDefault.length==0) {
-            sb.append("@");
-            sb.append(hashCode());
-        } else if (valsForDefault.length==1 && valsForDefault[0] instanceof Collection){
-            sb.append(Strings.toUniqueString(valsForDefault[0], 80));
-        } else {
-            sb.append("[");
-            boolean first = true;
-            for (Object x: valsForDefault) {
-                if (!first) sb.append(";");
-                else first = false;
-                sb.append(Strings.toUniqueString(x, 80));
-            }
-            sb.append("]");
-        }
-        return sb.toString(); 
-    }
-
-    @Override
-    public void start() {
-        if (log.isDebugEnabled()) log.debug("Starting feed {} for {}", this, entity);
-        if (activated) { 
-            throw new IllegalStateException(String.format("Attempt to start feed %s of entity %s when already running", 
-                    this, entity));
-        }
-        if (poller != null) {
-            throw new IllegalStateException(String.format("Attempt to re-start feed %s of entity %s", this, entity));
-        }
-        
-        poller = new Poller<Object>(entity, getConfig(ONLY_IF_SERVICE_UP));
-        activated = true;
-        preStart();
-        synchronized (pollerStateMutex) {
-            // don't start poller if we are suspended
-            if (!suspended) {
-                poller.start();
-            }
-        }
-    }
-
-    @Override
-    public void suspend() {
-        synchronized (pollerStateMutex) {
-            if (activated && !suspended) {
-                poller.stop();
-            }
-            suspended = true;
-        }
-    }
-    
-    @Override
-    public void resume() {
-        synchronized (pollerStateMutex) {
-            if (activated && suspended) {
-                poller.start();
-            }
-            suspended = false;
-        }
-    }
-    
-    @Override
-    public void destroy() {
-        stop();
-    }
-
-    @Override
-    public void stop() {
-        if (!activated) { 
-            log.debug("Ignoring attempt to stop feed {} of entity {} when not running", this, entity);
-            return;
-        }
-        if (log.isDebugEnabled()) log.debug("stopping feed {} for {}", this, entity);
-        
-        activated = false;
-        preStop();
-        synchronized (pollerStateMutex) {
-            if (!suspended) {
-                poller.stop();
-            }
-        }
-        postStop();
-        super.destroy();
-    }
-
-    @Override
-    public boolean isActivated() {
-        return activated;
-    }
-    
-    public EntityLocal getEntity() {
-        return entity;
-    }
-    
-    protected boolean isConnected() {
-        // TODO Default impl will result in multiple logs for same error if becomes unreachable
-        // (e.g. if ssh gets NoRouteToHostException, then every AttributePollHandler for that
-        // feed will log.warn - so if polling for 10 sensors/attributes will get 10 log messages).
-        // Would be nice if reduced this logging duplication.
-        // (You can reduce it by providing a better 'isConnected' implementation of course.)
-        return isRunning() && entity!=null && !((EntityInternal)entity).getManagementSupport().isNoLongerManaged();
-    }
-
-    @Override
-    public boolean isSuspended() {
-        return suspended;
-    }
-
-    @Override
-    public boolean isRunning() {
-        return isActivated() && !isSuspended() && !isDestroyed() && getPoller()!=null && getPoller().isRunning();
-    }
-
-    @Override
-    public RebindSupport<FeedMemento> getRebindSupport() {
-        return new BasicFeedRebindSupport(this);
-    }
-
-    @Override
-    protected void onChanged() {
-        // TODO Auto-generated method stub
-    }
-
-    /**
-     * For overriding.
-     */
-    protected void preStart() {
-    }
-    
-    /**
-     * For overriding.
-     */
-    protected void preStop() {
-    }
-    
-    /**
-     * For overriding.
-     */
-    protected void postStop() {
-    }
-    
-    /**
-     * For overriding, where sub-class can change return-type generics!
-     */
-    protected Poller<?> getPoller() {
-        return poller;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/AttributePollHandler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/AttributePollHandler.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/AttributePollHandler.java
deleted file mode 100644
index eac972e..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/AttributePollHandler.java
+++ /dev/null
@@ -1,248 +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.feed;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.core.entity.Attributes;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
-import org.apache.brooklyn.core.entity.lifecycle.Lifecycle.Transition;
-import org.apache.brooklyn.util.core.flags.TypeCoercions;
-import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.time.Duration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Objects;
-
-/**
- * Handler for when polling an entity's attribute. On each poll result the entity's attribute is set.
- * 
- * Calls to onSuccess and onError will happen sequentially, but may be called from different threads 
- * each time. Note that no guarantees of a synchronized block exist, so additional synchronization 
- * would be required for the Java memory model's "happens before" relationship.
- * 
- * @author aled
- */
-public class AttributePollHandler<V> implements PollHandler<V> {
-
-    public static final Logger log = LoggerFactory.getLogger(AttributePollHandler.class);
-
-    private final FeedConfig<V,?,?> config;
-    private final EntityLocal entity;
-    @SuppressWarnings("rawtypes")
-    private final AttributeSensor sensor;
-    private final AbstractFeed feed;
-    private final boolean suppressDuplicates;
-    
-    // allow 30 seconds before logging at WARN, if there has been no success yet;
-    // after success WARN immediately
-    // TODO these should both be configurable
-    private Duration logWarningGraceTimeOnStartup = Duration.THIRTY_SECONDS;
-    private Duration logWarningGraceTime = Duration.millis(0);
-    
-    // internal state to look after whether to log warnings
-    private volatile Long lastSuccessTime = null;
-    private volatile Long currentProblemStartTime = null;
-    private volatile boolean currentProblemLoggedAsWarning = false;
-    private volatile boolean lastWasProblem = false;
-
-    
-    public AttributePollHandler(FeedConfig<V,?,?> config, EntityLocal entity, AbstractFeed feed) {
-        this.config = checkNotNull(config, "config");
-        this.entity = checkNotNull(entity, "entity");
-        this.sensor = checkNotNull(config.getSensor(), "sensor");
-        this.feed = checkNotNull(feed, "feed");
-        this.suppressDuplicates = config.getSupressDuplicates();
-    }
-
-    @Override
-    public boolean checkSuccess(V val) {
-        // Always true if no checkSuccess predicate was configured.
-        return !config.hasCheckSuccessHandler() || config.getCheckSuccess().apply(val);
-    }
-
-    @Override
-    public void onSuccess(V val) {
-        if (lastWasProblem) {
-            if (currentProblemLoggedAsWarning) { 
-                log.info("Success (following previous problem) reading "+getBriefDescription());
-            } else {
-                log.debug("Success (following previous problem) reading "+getBriefDescription());
-            }
-            lastWasProblem = false;
-            currentProblemStartTime = null;
-            currentProblemLoggedAsWarning = false;
-        }
-        lastSuccessTime = System.currentTimeMillis();
-        if (log.isTraceEnabled()) log.trace("poll for {} got: {}", new Object[] {getBriefDescription(), val});
-        
-        try {
-            setSensor(transformValueOnSuccess(val));
-        } catch (Exception e) {
-            if (feed.isConnected()) {
-                log.warn("unable to compute "+getBriefDescription()+"; on val="+val, e);
-            } else {
-                if (log.isDebugEnabled()) log.debug("unable to compute "+getBriefDescription()+"; val="+val+" (when inactive)", e);
-            }
-        }
-    }
-
-    /** allows post-processing, such as applying a success handler; 
-     * default applies the onSuccess handler (which is recommended) */
-    protected Object transformValueOnSuccess(V val) {
-        return config.hasSuccessHandler() ? config.getOnSuccess().apply(val) : val;
-    }
-
-    @Override
-    public void onFailure(V val) {
-        if (!config.hasFailureHandler()) {
-            onException(new Exception("checkSuccess of "+this+" for "+getBriefDescription()+" was false but poller has no failure handler"));
-        } else {
-            logProblem("failure", val);
-
-            try {
-                setSensor(config.hasFailureHandler() ? config.getOnFailure().apply((V)val) : val);
-            } catch (Exception e) {
-                if (feed.isConnected()) {
-                    log.warn("Error computing " + getBriefDescription() + "; val=" + val+": "+ e, e);
-                } else {
-                    if (log.isDebugEnabled())
-                        log.debug("Error computing " + getBriefDescription() + "; val=" + val + " (when inactive)", e);
-                }
-            }
-        }
-    }
-
-    @Override
-    public void onException(Exception exception) {
-        if (!feed.isConnected()) {
-            if (log.isTraceEnabled()) log.trace("Read of {} in {} gave exception (while not connected or not yet connected): {}", new Object[] {this, getBriefDescription(), exception});
-        } else {
-            logProblem("exception", exception);
-        }
-
-        if (config.hasExceptionHandler()) {
-            try {
-                setSensor( config.getOnException().apply(exception) );
-            } catch (Exception e) {
-                if (feed.isConnected()) {
-                    log.warn("unable to compute "+getBriefDescription()+"; on exception="+exception, e);
-                } else {
-                    if (log.isDebugEnabled()) log.debug("unable to compute "+getBriefDescription()+"; exception="+exception+" (when inactive)", e);
-                }
-            }
-        }
-    }
-
-    protected void logProblem(String type, Object val) {
-        if (lastWasProblem && currentProblemLoggedAsWarning) {
-            if (log.isTraceEnabled())
-                log.trace("Recurring {} reading {} in {}: {}", new Object[] {type, this, getBriefDescription(), val});
-        } else {
-            long nowTime = System.currentTimeMillis();
-            // get a non-volatile value
-            Long currentProblemStartTimeCache = currentProblemStartTime;
-            long expiryTime = 
-                    (lastSuccessTime!=null && !isTransitioningOrStopped()) ? lastSuccessTime+logWarningGraceTime.toMilliseconds() :
-                    currentProblemStartTimeCache!=null ? currentProblemStartTimeCache+logWarningGraceTimeOnStartup.toMilliseconds() :
-                    nowTime+logWarningGraceTimeOnStartup.toMilliseconds();
-            if (!lastWasProblem) {
-                if (expiryTime <= nowTime) {
-                    currentProblemLoggedAsWarning = true;
-                    if (entity==null || !Entities.isNoLongerManaged(entity)) {
-                        log.warn("Read of " + getBriefDescription() + " gave " + type + ": " + val);
-                    } else {
-                        log.debug("Read of " + getBriefDescription() + " gave " + type + ": " + val);
-                    }
-                    if (log.isDebugEnabled() && val instanceof Throwable)
-                        log.debug("Trace for "+type+" reading "+getBriefDescription()+": "+val, (Throwable)val);
-                } else {
-                    if (log.isDebugEnabled())
-                        log.debug("Read of " + getBriefDescription() + " gave " + type + " (in grace period): " + val);
-                }
-                lastWasProblem = true;
-                currentProblemStartTime = nowTime;
-            } else {
-                if (expiryTime <= nowTime) {
-                    currentProblemLoggedAsWarning = true;
-                    log.warn("Read of " + getBriefDescription() + " gave " + type + 
-                            " (grace period expired, occurring for "+Duration.millis(nowTime - currentProblemStartTimeCache)+
-                            (config.hasExceptionHandler() ? "" : ", no exception handler set for sensor")+
-                            ")"+
-                            ": " + val);
-                    if (log.isDebugEnabled() && val instanceof Throwable)
-                        log.debug("Trace for "+type+" reading "+getBriefDescription()+": "+val, (Throwable)val);
-                } else {
-                    if (log.isDebugEnabled()) 
-                        log.debug("Recurring {} reading {} in {} (still in grace period): {}", new Object[] {type, this, getBriefDescription(), val});
-                }
-            }
-        }
-    }
-
-    protected boolean isTransitioningOrStopped() {
-        if (entity==null) return false;
-        Transition expected = entity.getAttribute(Attributes.SERVICE_STATE_EXPECTED);
-        if (expected==null) return false;
-        return (expected.getState()==Lifecycle.STARTING || expected.getState()==Lifecycle.STOPPING || expected.getState()==Lifecycle.STOPPED);
-    }
-
-    @SuppressWarnings("unchecked")
-    protected void setSensor(Object v) {
-        if (Entities.isNoLongerManaged(entity)) {
-            if (Tasks.isInterrupted()) return;
-            log.warn(""+entity+" is not managed; feed "+this+" setting "+sensor+" to "+v+" at this time is not supported ("+Tasks.current()+")");
-        }
-        
-        if (v == FeedConfig.UNCHANGED) {
-            // nothing
-        } else if (v == FeedConfig.REMOVE) {
-            ((EntityInternal)entity).removeAttribute(sensor);
-        } else if (sensor == FeedConfig.NO_SENSOR) {
-            // nothing
-        } else {
-            Object coercedV = TypeCoercions.coerce(v, sensor.getType());
-            if (suppressDuplicates && Objects.equal(coercedV, entity.getAttribute(sensor))) {
-                // no change; nothing
-            } else {
-                entity.setAttribute(sensor, coercedV);
-            }
-        }
-    }
-
-    @Override
-    public String toString() {
-        return super.toString()+"["+getDescription()+"]";
-    }
-    
-    @Override
-    public String getDescription() {
-        return sensor.getName()+" @ "+entity.getId()+" <- "+config;
-    }
-    
-    protected String getBriefDescription() {
-        return ""+entity+"->"+(sensor==FeedConfig.NO_SENSOR ? "(dynamic sensors)" : ""+sensor);
-    }
-        
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/ConfigToAttributes.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/ConfigToAttributes.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/ConfigToAttributes.java
deleted file mode 100644
index 7938cc4..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/ConfigToAttributes.java
+++ /dev/null
@@ -1,59 +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.feed;
-
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.mgmt.ManagementContext;
-import org.apache.brooklyn.api.sensor.Sensor;
-import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
-import org.apache.brooklyn.core.sensor.TemplatedStringAttributeSensorAndConfigKey;
-
-
-/** Simple config adapter for setting {@link AttributeSensorAndConfigKey} sensor values from the config value or config default */ 
-public class ConfigToAttributes {
-
-    //normally just applied once, statically, not registered...
-    public static void apply(EntityLocal entity) {
-        for (Sensor<?> it : entity.getEntityType().getSensors()) {
-            if (it instanceof AttributeSensorAndConfigKey) {
-                apply(entity, (AttributeSensorAndConfigKey<?,?>)it);
-            }
-        }
-    }
-
-    /**
-     * Convenience for ensuring an individual sensor is set from its config key
-     * (e.g. sub-classes of DynamicWebAppCluster that don't want to set HTTP_PORT etc!)
-     */
-    public static <T> T apply(EntityLocal entity, AttributeSensorAndConfigKey<?,T> key) {
-        T v = entity.getAttribute(key);
-        if (v!=null) return v;
-        v = key.getAsSensorValue(entity);
-        if (v!=null) entity.setAttribute(key, v);
-        return v;
-    }
-
-    /**
-     * Convenience for transforming a config value (e.g. processing a {@link TemplatedStringAttributeSensorAndConfigKey}),
-     * outside of the context of an entity.
-     */
-    public static <T> T transform(ManagementContext managementContext, AttributeSensorAndConfigKey<?,T> key) {
-        return key.getAsSensorValue(managementContext);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/DelegatingPollHandler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/DelegatingPollHandler.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/DelegatingPollHandler.java
deleted file mode 100644
index 4433e83..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/DelegatingPollHandler.java
+++ /dev/null
@@ -1,96 +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.feed;
-
-import java.util.List;
-
-import com.google.common.collect.ImmutableList;
-
-/**
- * A poll handler that delegates each call to a set of poll handlers.
- * 
- * @author aled
- */
-public class DelegatingPollHandler<V> implements PollHandler<V> {
-
-    private final List<AttributePollHandler<? super V>> delegates;
-
-    public DelegatingPollHandler(Iterable<AttributePollHandler<? super V>> delegates) {
-        super();
-        this.delegates = ImmutableList.copyOf(delegates);
-    }
-
-    @Override
-    public boolean checkSuccess(V val) {
-        for (AttributePollHandler<? super V> delegate : delegates) {
-            if (!delegate.checkSuccess(val))
-                return false;
-        }
-        return true;
-    }
-
-    @Override
-    public void onSuccess(V val) {
-        for (AttributePollHandler<? super V> delegate : delegates) {
-            delegate.onSuccess(val);
-        }
-    }
-
-    @Override
-    public void onFailure(V val) {
-        for (AttributePollHandler<? super V> delegate : delegates) {
-            delegate.onFailure(val);
-        }
-    }
-
-    @Override
-    public void onException(Exception exception) {
-        for (AttributePollHandler<? super V> delegate : delegates) {
-            delegate.onException(exception);
-        }
-    }
-    
-    @Override
-    public String toString() {
-        return super.toString()+"["+getDescription()+"]";
-    }
-    
-    @Override
-    public String getDescription() {
-        if (delegates.isEmpty())
-            return "(empty delegate list)";
-        if (delegates.size()==1) 
-            return delegates.get(0).getDescription();
-        StringBuilder sb = new StringBuilder();
-        sb.append("[");
-        int count = 0;
-        for (AttributePollHandler<? super V> delegate : delegates) {
-            if (count>0) sb.append("; ");
-            sb.append(delegate.getDescription());
-            if (count>2) {
-                sb.append("; ...");
-                break;
-            }
-            count++;
-        }
-        sb.append("]");
-        return sb.toString();
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/FeedConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/FeedConfig.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/FeedConfig.java
deleted file mode 100644
index 32ea2ab..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/FeedConfig.java
+++ /dev/null
@@ -1,297 +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.feed;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.sensor.Sensors;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.util.collections.MutableList;
-import org.apache.brooklyn.util.guava.Functionals;
-import org.apache.brooklyn.util.javalang.JavaClassNames;
-import org.apache.brooklyn.util.text.Strings;
-
-import com.google.common.base.Function;
-import com.google.common.base.Functions;
-import com.google.common.base.Objects;
-import com.google.common.base.Predicate;
-
-/**
- * Configuration for a poll, or a subscription etc, that is being added to a feed.
- * 
- * @author aled
- */
-public class FeedConfig<V, T, F extends FeedConfig<V, T, F>> {
-
-    /** The onSuccess or onError functions can return this value to indicate that the sensor should not change. 
-     * @deprecated since 0.7.0 use UNCHANGED */
-    public static final Object UNSET = Entities.UNCHANGED;
-    /** The onSuccess or onError functions can return this value to indicate that the sensor should not change. */ 
-    public static final Object UNCHANGED = Entities.UNCHANGED;
-    /** The onSuccess or onError functions can return this value to indicate that the sensor value should be removed
-     * (cf 'null', but useful in dynamic situations) */ 
-    public static final Object REMOVE = Entities.REMOVE;
-    
-    /** Indicates that no sensor is being used here. This sensor is suppressed,
-     * but is useful where you want to use the feeds with custom success/exception/failure functions
-     * which directly set multiple sensors, e.g. dynamically based on the poll response.
-     * <p>
-     * See {@link HttpPollConfig#forMultiple()} and its usages.
-     * (It can work for any poll config, but conveniences have not been supplied for others.)  */
-    public static final AttributeSensor<Void> NO_SENSOR = Sensors.newSensor(Void.class, "brooklyn.no.sensor");
-    
-    private final AttributeSensor<T> sensor;
-    private Function<? super V, T> onsuccess;
-    private Function<? super V, T> onfailure;
-    private Function<? super Exception, T> onexception;
-    private Predicate<? super V> checkSuccess;
-    private boolean suppressDuplicates;
-    private boolean enabled = true;
-    
-    public FeedConfig(AttributeSensor<T> sensor) {
-        this.sensor = checkNotNull(sensor, "sensor");
-    }
-
-    public FeedConfig(FeedConfig<V, T, F> other) {
-        this.sensor = other.sensor;
-        this.onsuccess = other.onsuccess;
-        this.onfailure = other.onfailure;
-        this.onexception = other.onexception;
-        this.checkSuccess = other.checkSuccess;
-        this.suppressDuplicates = other.suppressDuplicates;
-        this.enabled = other.enabled;
-    }
-
-    @SuppressWarnings("unchecked")
-    protected F self() {
-        return (F) this;
-    }
-    
-    public AttributeSensor<T> getSensor() {
-        return sensor;
-    }
-
-    public Predicate<? super V> getCheckSuccess() {
-        return checkSuccess;
-    }
-    
-    public Function<? super V, T> getOnSuccess() {
-        return onsuccess;
-    }
-
-    public Function<? super V, T> getOnFailure() {
-        return onfailure;
-    }
-    
-    public Function<? super Exception, T> getOnException() {
-        return onexception;
-    }
-
-    public boolean getSupressDuplicates() {
-        return suppressDuplicates;
-    }
-    
-    public boolean isEnabled() {
-        return enabled;
-    }
-    
-    /** sets the predicate used to check whether a feed run is successful */
-    public F checkSuccess(Predicate<? super V> val) {
-        this.checkSuccess = checkNotNull(val, "checkSuccess");
-        return self();
-    }
-    /** as {@link #checkSuccess(Predicate)} */
-    public F checkSuccess(final Function<? super V,Boolean> val) {
-        return checkSuccess(Functionals.predicate(val));
-    }
-    @SuppressWarnings("unused")
-    /** @deprecated since 0.7.0, kept for rebind */ @Deprecated
-    private F checkSuccessLegacy(final Function<? super V,Boolean> val) {
-        return checkSuccess(new Predicate<V>() {
-            @Override
-            public boolean apply(V input) {
-                return val.apply(input);
-            }
-        });
-    }
-
-    public F onSuccess(Function<? super V,T> val) {
-        this.onsuccess = checkNotNull(val, "onSuccess");
-        return self();
-    }
-    
-    public F setOnSuccess(T val) {
-        return onSuccess(Functions.constant(val));
-    }
-    
-    /** a failure is when the connection is fine (no exception) but the other end returns a result object V 
-     * which the feed can tell indicates a failure (e.g. HTTP code 404) */
-    public F onFailure(Function<? super V,T> val) {
-        this.onfailure = checkNotNull(val, "onFailure");
-        return self();
-    }
-
-    public F setOnFailure(T val) {
-        return onFailure(Functions.constant(val));
-    }
-
-    /** registers a callback to be used {@link #onSuccess(Function)} and {@link #onFailure(Function)}, 
-     * i.e. whenever a result comes back, but not in case of exceptions being thrown (ie problems communicating) */
-    public F onResult(Function<? super V, T> val) {
-        onSuccess(val);
-        return onFailure(val);
-    }
-
-    public F setOnResult(T val) {
-        return onResult(Functions.constant(val));
-    }
-
-    /** an exception is when there is an error in the communication */
-    public F onException(Function<? super Exception,T> val) {
-        this.onexception = checkNotNull(val, "onException");
-        return self();
-    }
-    
-    public F setOnException(T val) {
-        return onException(Functions.constant(val));
-    }
-
-    /** convenience for indicating a behaviour to occur for both
-     * {@link #onException(Function)}
-     * (error connecting) and 
-     * {@link #onFailure(Function)} 
-     * (successful communication but failure report from remote end) */
-    public F onFailureOrException(Function<Object,T> val) {
-        onFailure(val);
-        return onException(val);
-    }
-    
-    public F setOnFailureOrException(T val) {
-        return onFailureOrException(Functions.constant(val));
-    }
-
-    public F suppressDuplicates(boolean val) {
-        suppressDuplicates = val;
-        return self();
-    }
-    
-    /**
-     * Whether this feed is enabled (defaulting to true).
-     */
-    public F enabled(boolean val) {
-        enabled = val;
-        return self();
-    }
-    
-    public boolean hasSuccessHandler() {
-        return this.onsuccess != null;
-    }
-
-    public boolean hasFailureHandler() {
-        return this.onfailure != null;
-    }
-
-    public boolean hasExceptionHandler() {
-        return this.onexception != null;
-    }
-
-    public boolean hasCheckSuccessHandler() {
-        return this.checkSuccess != null;
-    }
-
-    
-    @Override
-    public String toString() {
-        StringBuilder result = new StringBuilder();
-        result.append(toStringBaseName());
-        result.append("[");
-        boolean contents = false;
-        Object source = toStringPollSource();
-        AttributeSensor<T> s = getSensor();
-        if (Strings.isNonBlank(Strings.toString(source))) {
-            result.append(Strings.toUniqueString(source, 40));
-            if (s!=null) {
-                result.append("->");
-                result.append(s.getName());
-            }
-            contents = true;
-        } else if (s!=null) {
-            result.append(s.getName());
-            contents = true;
-        }
-        MutableList<Object> fields = toStringOtherFields();
-        if (fields!=null) {
-            for (Object field: fields) {
-                if (Strings.isNonBlank(Strings.toString(field))) {
-                    if (contents) result.append(";");
-                    contents = true;
-                    result.append(field);
-                }
-            }
-        }
-        result.append("]");
-        return result.toString();
-    }
-
-    /** can be overridden to supply a simpler base name than the class name */
-    protected String toStringBaseName() {
-        return JavaClassNames.simpleClassName(this);
-    }
-    /** can be overridden to supply add'l info for the {@link #toString()}; subclasses can add to the returned value */
-    protected MutableList<Object> toStringOtherFields() {
-        return MutableList.<Object>of();
-    }
-    /** can be overridden to supply add'l info for the {@link #toString()}, placed before the sensor with -> */
-    protected Object toStringPollSource() {
-        return null;
-    }
-    /** all configs should supply a unique tag element, inserted into the feed */
-    protected String getUniqueTag() {
-        return toString();
-    }
-
-    /** returns fields which should be used for equality, including by default {@link #toStringOtherFields()} and {@link #toStringPollSource()};
-     * subclasses can add to the returned value */
-    protected MutableList<Object> equalsFields() {
-        MutableList<Object> result = MutableList.of().appendIfNotNull(getSensor()).appendIfNotNull(toStringPollSource());
-        for (Object field: toStringOtherFields()) result.appendIfNotNull(field);
-        return result;
-    }
-
-    @Override
-    public int hashCode() { 
-        int hc = super.hashCode();
-        for (Object f: equalsFields())
-            hc = Objects.hashCode(hc, f);
-        return hc;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) return true;
-        if (!super.equals(obj)) return false;
-        PollConfig<?,?,?> other = (PollConfig<?,?,?>) obj;
-        if (!Objects.equal(getUniqueTag(), other.getUniqueTag())) return false;
-        if (!Objects.equal(equalsFields(), other.equalsFields())) return false;
-        return true;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/PollConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/PollConfig.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/PollConfig.java
deleted file mode 100644
index 01a561b..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/PollConfig.java
+++ /dev/null
@@ -1,85 +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.feed;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-import java.util.concurrent.TimeUnit;
-
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.util.collections.MutableList;
-import org.apache.brooklyn.util.time.Duration;
-
-/**
- * Configuration for polling, which is being added to a feed (e.g. to poll a given URL over http).
- * 
- * @author aled
- */
-public class PollConfig<V, T, F extends PollConfig<V, T, F>> extends FeedConfig<V, T, F> {
-
-    private long period = -1;
-    private String description;
-
-    public PollConfig(AttributeSensor<T> sensor) {
-        super(sensor);
-    }
-
-    public PollConfig(PollConfig<V,T,F> other) {
-        super(other);
-        this.period = other.period;
-    }
-
-    public long getPeriod() {
-        return period;
-    }
-    
-    public F period(Duration val) {
-        checkArgument(val.toMilliseconds() >= 0, "period must be greater than or equal to zero");
-        this.period = val.toMilliseconds();
-        return self();
-    }
-    
-    public F period(long val) {
-        checkArgument(val >= 0, "period must be greater than or equal to zero");
-        this.period = val; return self();
-    }
-    
-    public F period(long val, TimeUnit units) {
-        checkArgument(val >= 0, "period must be greater than or equal to zero");
-        return period(units.toMillis(val));
-    }
-    
-    public F description(String description) {
-        this.description = description;
-        return self();
-    }
-    
-    public String getDescription() {
-        return description;
-    }
-    
-    @Override protected MutableList<Object> toStringOtherFields() {
-        return super.toStringOtherFields().appendIfNotNull(description);
-    }
-
-    @Override
-    protected MutableList<Object> equalsFields() {
-        return super.equalsFields().appendIfNotNull(period);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/PollHandler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/PollHandler.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/PollHandler.java
deleted file mode 100644
index 175c76f..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/PollHandler.java
+++ /dev/null
@@ -1,38 +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.feed;
-
-/**
- * Notified by the Poller of the result for each job, on each poll.
- * 
- * @author aled
- */
-public interface PollHandler<V> {
-
-    public boolean checkSuccess(V val);
-
-    public void onSuccess(V val);
-
-    public void onFailure(V val);
-
-    public void onException(Exception exception);
-
-    public String getDescription();
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/Poller.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/Poller.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/Poller.java
deleted file mode 100644
index f6e8e24..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/Poller.java
+++ /dev/null
@@ -1,205 +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.feed;
-
-import java.util.LinkedHashSet;
-import java.util.Set;
-import java.util.concurrent.Callable;
-
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.mgmt.Task;
-import org.apache.brooklyn.core.entity.Attributes;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.task.DynamicSequentialTask;
-import org.apache.brooklyn.util.core.task.ScheduledTask;
-import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.time.Duration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Objects;
-
-
-/** 
- * For executing periodic polls.
- * Jobs are added to the schedule, and then the poller is started.
- * The jobs will then be executed periodically, and the handler called for the result/failure.
- * 
- * Assumes the schedule+start will be done single threaded, and that stop will not be done concurrently.
- */
-public class Poller<V> {
-    public static final Logger log = LoggerFactory.getLogger(Poller.class);
-
-    private final EntityLocal entity;
-    private final boolean onlyIfServiceUp;
-    private final Set<Callable<?>> oneOffJobs = new LinkedHashSet<Callable<?>>();
-    private final Set<PollJob<V>> pollJobs = new LinkedHashSet<PollJob<V>>();
-    private final Set<Task<?>> oneOffTasks = new LinkedHashSet<Task<?>>();
-    private final Set<ScheduledTask> tasks = new LinkedHashSet<ScheduledTask>();
-    private volatile boolean started = false;
-    
-    private static class PollJob<V> {
-        final PollHandler<? super V> handler;
-        final Duration pollPeriod;
-        final Runnable wrappedJob;
-        private boolean loggedPreviousException = false;
-        
-        PollJob(final Callable<V> job, final PollHandler<? super V> handler, Duration period) {
-            this.handler = handler;
-            this.pollPeriod = period;
-            
-            wrappedJob = new Runnable() {
-                public void run() {
-                    try {
-                        V val = job.call();
-                        loggedPreviousException = false;
-                        if (handler.checkSuccess(val)) {
-                            handler.onSuccess(val);
-                        } else {
-                            handler.onFailure(val);
-                        }
-                    } catch (Exception e) {
-                        if (loggedPreviousException) {
-                            if (log.isTraceEnabled()) log.trace("PollJob for {}, repeated consecutive failures, handling {} using {}", new Object[] {job, e, handler});
-                        } else {
-                            if (log.isDebugEnabled()) log.debug("PollJob for {} handling {} using {}", new Object[] {job, e, handler});
-                            loggedPreviousException = true;
-                        }
-                        handler.onException(e);
-                    }
-                }
-            };
-        }
-    }
-    
-    /** @deprecated since 0.7.0, pass in whether should run onlyIfServiceUp */
-    @Deprecated
-    public Poller(EntityLocal entity) {
-        this(entity, false);
-    }
-    public Poller(EntityLocal entity, boolean onlyIfServiceUp) {
-        this.entity = entity;
-        this.onlyIfServiceUp = onlyIfServiceUp;
-    }
-    
-    /** Submits a one-off poll job; recommended that callers supply to-String so that task has a decent description */
-    public void submit(Callable<?> job) {
-        if (started) {
-            throw new IllegalStateException("Cannot submit additional tasks after poller has started");
-        }
-        oneOffJobs.add(job);
-    }
-
-    public void scheduleAtFixedRate(Callable<V> job, PollHandler<? super V> handler, long period) {
-        scheduleAtFixedRate(job, handler, Duration.millis(period));
-    }
-    public void scheduleAtFixedRate(Callable<V> job, PollHandler<? super V> handler, Duration period) {
-        if (started) {
-            throw new IllegalStateException("Cannot schedule additional tasks after poller has started");
-        }
-        PollJob<V> foo = new PollJob<V>(job, handler, period);
-        pollJobs.add(foo);
-    }
-
-    @SuppressWarnings({ "unchecked" })
-    public void start() {
-        // TODO Previous incarnation of this logged this logged polledSensors.keySet(), but we don't know that anymore
-        // Is that ok, are can we do better?
-        
-        if (log.isDebugEnabled()) log.debug("Starting poll for {} (using {})", new Object[] {entity, this});
-        if (started) { 
-            throw new IllegalStateException(String.format("Attempt to start poller %s of entity %s when already running", 
-                    this, entity));
-        }
-        
-        started = true;
-        
-        for (final Callable<?> oneOffJob : oneOffJobs) {
-            Task<?> task = Tasks.builder().dynamic(false).body((Callable<Object>) oneOffJob).name("Poll").description("One-time poll job "+oneOffJob).build();
-            oneOffTasks.add(((EntityInternal)entity).getExecutionContext().submit(task));
-        }
-        
-        for (final PollJob<V> pollJob : pollJobs) {
-            final String scheduleName = pollJob.handler.getDescription();
-            if (pollJob.pollPeriod.compareTo(Duration.ZERO) > 0) {
-                Callable<Task<?>> pollingTaskFactory = new Callable<Task<?>>() {
-                    public Task<?> call() {
-                        DynamicSequentialTask<Void> task = new DynamicSequentialTask<Void>(MutableMap.of("displayName", scheduleName, "entity", entity), 
-                            new Callable<Void>() { public Void call() {
-                                if (onlyIfServiceUp && !Boolean.TRUE.equals(entity.getAttribute(Attributes.SERVICE_UP))) {
-                                        return null;
-                                }
-                                pollJob.wrappedJob.run();
-                                return null; 
-                            } } );
-                        BrooklynTaskTags.setTransient(task);
-                        return task;
-                    }
-                };
-                ScheduledTask task = new ScheduledTask(MutableMap.of("period", pollJob.pollPeriod, "displayName", "scheduled:"+scheduleName), pollingTaskFactory);
-                tasks.add((ScheduledTask)Entities.submit(entity, task));
-            } else {
-                if (log.isDebugEnabled()) log.debug("Activating poll (but leaving off, as period {}) for {} (using {})", new Object[] {pollJob.pollPeriod, entity, this});
-            }
-        }
-    }
-    
-    public void stop() {
-        if (log.isDebugEnabled()) log.debug("Stopping poll for {} (using {})", new Object[] {entity, this});
-        if (!started) { 
-            throw new IllegalStateException(String.format("Attempt to stop poller %s of entity %s when not running", 
-                    this, entity));
-        }
-        
-        started = false;
-        for (Task<?> task : oneOffTasks) {
-            if (task != null) task.cancel(true);
-        }
-        for (ScheduledTask task : tasks) {
-            if (task != null) task.cancel();
-        }
-        oneOffTasks.clear();
-        tasks.clear();
-    }
-
-    public boolean isRunning() {
-        boolean hasActiveTasks = false;
-        for (Task<?> task: tasks) {
-            if (task.isBegun() && !task.isDone()) {
-                hasActiveTasks = true;
-                break;
-            }
-        }
-        if (!started && hasActiveTasks) {
-            log.warn("Poller should not be running, but has active tasks, tasks: "+tasks);
-        }
-        return started && hasActiveTasks;
-    }
-    
-    protected boolean isEmpty() {
-        return pollJobs.isEmpty();
-    }
-    
-    public String toString() {
-        return Objects.toStringHelper(this).add("entity", entity).toString();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/function/FunctionFeed.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/function/FunctionFeed.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/function/FunctionFeed.java
deleted file mode 100644
index 1cb6861..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/function/FunctionFeed.java
+++ /dev/null
@@ -1,208 +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.feed.function;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.sensor.feed.AbstractFeed;
-import org.apache.brooklyn.sensor.feed.AttributePollHandler;
-import org.apache.brooklyn.sensor.feed.DelegatingPollHandler;
-import org.apache.brooklyn.util.time.Duration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Objects;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.SetMultimap;
-import com.google.common.collect.Sets;
-import com.google.common.reflect.TypeToken;
-
-/**
- * Provides a feed of attribute values, by periodically invoking functions.
- * 
- * Example usage (e.g. in an entity that extends SoftwareProcessImpl):
- * <pre>
- * {@code
- * private FunctionFeed feed;
- * 
- * //@Override
- * protected void connectSensors() {
- *   super.connectSensors();
- *   
- *   feed = FunctionFeed.builder()
- *     .entity(this)
- *     .poll(new FunctionPollConfig<Object, Boolean>(SERVICE_UP)
- *         .period(500, TimeUnit.MILLISECONDS)
- *         .callable(new Callable<Boolean>() {
- *             public Boolean call() throws Exception {
- *               return getDriver().isRunning();
- *             }
- *         })
- *         .onExceptionOrFailure(Functions.constant(Boolan.FALSE))
- *     .build();
- * }
- * 
- * {@literal @}Override
- * protected void disconnectSensors() {
- *   super.disconnectSensors();
- *   if (feed != null) feed.stop();
- * }
- * }
- * </pre>
- * 
- * @author aled
- */
-public class FunctionFeed extends AbstractFeed {
-
-    private static final Logger log = LoggerFactory.getLogger(FunctionFeed.class);
-
-    // Treat as immutable once built
-    @SuppressWarnings("serial")
-    public static final ConfigKey<SetMultimap<FunctionPollIdentifier, FunctionPollConfig<?,?>>> POLLS = ConfigKeys.newConfigKey(
-            new TypeToken<SetMultimap<FunctionPollIdentifier, FunctionPollConfig<?,?>>>() {},
-            "polls");
-
-    public static Builder builder() {
-        return new Builder();
-    }
-    
-    public static Builder builder(String uniqueTag) {
-        return new Builder().uniqueTag(uniqueTag);
-    }
-    
-    public static class Builder {
-        private EntityLocal entity;
-        private boolean onlyIfServiceUp = false;
-        private long period = 500;
-        private TimeUnit periodUnits = TimeUnit.MILLISECONDS;
-        private List<FunctionPollConfig<?,?>> polls = Lists.newArrayList();
-        private String uniqueTag;
-        private volatile boolean built;
-
-        public Builder entity(EntityLocal val) {
-            this.entity = val;
-            return this;
-        }
-        public Builder onlyIfServiceUp() { return onlyIfServiceUp(true); }
-        public Builder onlyIfServiceUp(boolean onlyIfServiceUp) { 
-            this.onlyIfServiceUp = onlyIfServiceUp; 
-            return this; 
-        }
-        public Builder period(Duration d) {
-            return period(d.toMilliseconds(), TimeUnit.MILLISECONDS);
-        }
-        public Builder period(long millis) {
-            return period(millis, TimeUnit.MILLISECONDS);
-        }
-        public Builder period(long val, TimeUnit units) {
-            this.period = val;
-            this.periodUnits = units;
-            return this;
-        }
-        public Builder poll(FunctionPollConfig<?,?> config) {
-            polls.add(config);
-            return this;
-        }
-        public Builder uniqueTag(String uniqueTag) {
-            this.uniqueTag = uniqueTag;
-            return this;
-        }
-        public FunctionFeed build() {
-            built = true;
-            FunctionFeed result = new FunctionFeed(this);
-            result.setEntity(checkNotNull(entity, "entity"));
-            result.start();
-            return result;
-        }
-        @Override
-        protected void finalize() {
-            if (!built) log.warn("FunctionFeed.Builder created, but build() never called");
-        }
-    }
-    
-    private static class FunctionPollIdentifier {
-        final Callable<?> job;
-
-        private FunctionPollIdentifier(Callable<?> job) {
-            this.job = checkNotNull(job, "job");
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hashCode(job);
-        }
-        
-        @Override
-        public boolean equals(Object other) {
-            return (other instanceof FunctionPollIdentifier) && Objects.equal(job, ((FunctionPollIdentifier)other).job);
-        }
-    }
-
-    /**
-     * For rebind; do not call directly; use builder
-     */
-    public FunctionFeed() {
-    }
-    
-    protected FunctionFeed(Builder builder) {
-        setConfig(ONLY_IF_SERVICE_UP, builder.onlyIfServiceUp);
-        
-        SetMultimap<FunctionPollIdentifier, FunctionPollConfig<?,?>> polls = HashMultimap.<FunctionPollIdentifier,FunctionPollConfig<?,?>>create();
-        for (FunctionPollConfig<?,?> config : builder.polls) {
-            if (!config.isEnabled()) continue;
-            @SuppressWarnings({ "rawtypes", "unchecked" })
-            FunctionPollConfig<?,?> configCopy = new FunctionPollConfig(config);
-            if (configCopy.getPeriod() < 0) configCopy.period(builder.period, builder.periodUnits);
-            Callable<?> job = config.getCallable();
-            polls.put(new FunctionPollIdentifier(job), configCopy);
-        }
-        setConfig(POLLS, polls);
-        initUniqueTag(builder.uniqueTag, polls.values());
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Override
-    protected void preStart() {
-        SetMultimap<FunctionPollIdentifier, FunctionPollConfig<?, ?>> polls = getConfig(POLLS);
-        for (final FunctionPollIdentifier pollInfo : polls.keySet()) {
-            Set<FunctionPollConfig<?,?>> configs = polls.get(pollInfo);
-            long minPeriod = Integer.MAX_VALUE;
-            Set<AttributePollHandler<?>> handlers = Sets.newLinkedHashSet();
-
-            for (FunctionPollConfig<?,?> config : configs) {
-                handlers.add(new AttributePollHandler(config, entity, this));
-                if (config.getPeriod() > 0) minPeriod = Math.min(minPeriod, config.getPeriod());
-            }
-            
-            getPoller().scheduleAtFixedRate(
-                    (Callable)pollInfo.job,
-                    new DelegatingPollHandler(handlers), 
-                    minPeriod);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/function/FunctionPollConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/function/FunctionPollConfig.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/function/FunctionPollConfig.java
deleted file mode 100644
index 7b91988..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/function/FunctionPollConfig.java
+++ /dev/null
@@ -1,111 +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.feed.function;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import groovy.lang.Closure;
-
-import java.util.concurrent.Callable;
-
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.sensor.feed.FeedConfig;
-import org.apache.brooklyn.sensor.feed.PollConfig;
-import org.apache.brooklyn.util.groovy.GroovyJavaMethods;
-import org.apache.brooklyn.util.guava.Functionals;
-import org.apache.brooklyn.util.javalang.JavaClassNames;
-
-import com.google.common.base.Supplier;
-
-public class FunctionPollConfig<S, T> extends PollConfig<S, T, FunctionPollConfig<S, T>> {
-
-    private Callable<?> callable;
-    
-    public static <T> FunctionPollConfig<?, T> forSensor(AttributeSensor<T> sensor) {
-        return new FunctionPollConfig<Object, T>(sensor);
-    }
-    
-    public FunctionPollConfig(AttributeSensor<T> sensor) {
-        super(sensor);
-    }
-
-    public FunctionPollConfig(FunctionPollConfig<S, T> other) {
-        super(other);
-        callable = other.callable;
-    }
-    
-    public Callable<? extends Object> getCallable() {
-        return callable;
-    }
-    
-    /**
-     * The {@link Callable} to be invoked on each poll.
-     * <p>
-     * Note this <em>must</em> use generics, otherwise the return type of subsequent chained
-     * calls will (e.g. to {@link FeedConfig#onException(com.google.common.base.Function)} will
-     * return the wrong type.
-     */
-    @SuppressWarnings("unchecked")
-    public <newS> FunctionPollConfig<newS, T> callable(Callable<? extends newS> val) {
-        this.callable = checkNotNull(val, "callable");
-        return (FunctionPollConfig<newS, T>) this;
-    }
-    
-    /**
-     * Supplies the value to be returned by each poll.
-     * <p>
-     * Note this <em>must</em> use generics, otherwise the return type of subsequent chained
-     * calls will (e.g. to {@link FeedConfig#onException(com.google.common.base.Function)} will
-     * return the wrong type.
-     */
-    @SuppressWarnings("unchecked")
-    public <newS> FunctionPollConfig<newS, T> supplier(final Supplier<? extends newS> val) {
-        this.callable = Functionals.callable( checkNotNull(val, "supplier") );
-        return (FunctionPollConfig<newS, T>) this;
-    }
-    
-    /** @deprecated since 0.7.0, kept for legacy compatibility when deserializing */
-    @SuppressWarnings({ "unchecked", "unused" })
-    private <newS> FunctionPollConfig<newS, T> supplierLegacy(final Supplier<? extends newS> val) {
-        checkNotNull(val, "supplier");
-        this.callable = new Callable<newS>() {
-            @Override
-            public newS call() throws Exception {
-                return val.get();
-            }
-        };
-        return (FunctionPollConfig<newS, T>) this;
-    }
-
-    public FunctionPollConfig<S, T> closure(Closure<?> val) {
-        this.callable = GroovyJavaMethods.callableFromClosure(checkNotNull(val, "closure"));
-        return this;
-    }
-
-    @Override protected String toStringBaseName() { return "fn"; }
-    @Override protected String toStringPollSource() {
-        if (callable==null) return null;
-        String cs = callable.toString();
-        if (!cs.contains( ""+Integer.toHexString(callable.hashCode()) )) {
-            return cs;
-        }
-        // if hashcode is in callable it's probably a custom internal; return class name
-        return JavaClassNames.simpleClassName(callable);
-    }
-
-}


[32/36] incubator-brooklyn git commit: Rename o.a.b.sensor.enricher to o.a.b.core.enricher

Posted by he...@apache.org.
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;
-    }
-}


[28/36] incubator-brooklyn git commit: Rename o.a.b.sensor.enricher to o.a.b.core.enricher

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/sensor/enricher/TransformingEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/enricher/TransformingEnricherTest.java b/core/src/test/java/org/apache/brooklyn/sensor/enricher/TransformingEnricherTest.java
deleted file mode 100644
index d020a25..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/enricher/TransformingEnricherTest.java
+++ /dev/null
@@ -1,71 +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.entity.EntitySpec;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.core.location.SimulatedLocation;
-import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
-import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.apache.brooklyn.util.math.MathFunctions;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableList;
-
-public class TransformingEnricherTest extends BrooklynAppUnitTestSupport {
-
-    public static final Logger log = LoggerFactory.getLogger(TransformingEnricherTest.class);
-            
-    TestEntity producer;
-    AttributeSensor<Integer> intSensorA;
-    AttributeSensor<Long> target;
-
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        producer = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        intSensorA = new BasicAttributeSensor<Integer>(Integer.class, "int.sensor.a");
-        target = new BasicAttributeSensor<Long>(Long.class, "long.sensor.target");
-        
-        app.start(ImmutableList.of(new SimulatedLocation()));
-    }
-    
-    @Test
-    public void testTransformingEnricher() throws Exception {
-        //ensure previous values get picked up
-        producer.setAttribute(intSensorA, 3);
-
-        producer.addEnricher(Enrichers.builder()
-                .transforming(intSensorA)
-                //.computing(MathFunctions.times(2)) // TODO calling it before "publishing" means it doesn't check return type!
-                .publishing(target)
-                .computing((Function)MathFunctions.times(2)) // TODO doesn't match strongly typed int->long
-                .build());
-
-        EntityTestUtils.assertAttributeEqualsEventually(producer, target, 6L);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/sensor/enricher/YamlRollingTimeWindowMeanEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/enricher/YamlRollingTimeWindowMeanEnricherTest.java b/core/src/test/java/org/apache/brooklyn/sensor/enricher/YamlRollingTimeWindowMeanEnricherTest.java
deleted file mode 100644
index e7fbcd6..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/enricher/YamlRollingTimeWindowMeanEnricherTest.java
+++ /dev/null
@@ -1,179 +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 org.testng.Assert.assertEquals;
-
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.mgmt.SubscriptionContext;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.api.sensor.EnricherSpec;
-import org.apache.brooklyn.core.entity.AbstractApplication;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
-import org.apache.brooklyn.core.sensor.BasicSensorEvent;
-import org.apache.brooklyn.entity.stock.BasicEntity;
-import org.apache.brooklyn.sensor.enricher.YamlRollingTimeWindowMeanEnricher;
-import org.apache.brooklyn.sensor.enricher.YamlTimeWeightedDeltaEnricher;
-import org.apache.brooklyn.sensor.enricher.YamlRollingTimeWindowMeanEnricher.ConfidenceQualifiedNumber;
-import org.apache.brooklyn.util.time.Duration;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-public class YamlRollingTimeWindowMeanEnricherTest {
-    
-    AbstractApplication app;
-    
-    BasicEntity producer;
-
-    AttributeSensor<Integer> intSensor;
-    AttributeSensor<Double> avgSensor, deltaSensor;
-    
-    Duration timePeriod = Duration.ONE_SECOND;
-    
-    YamlTimeWeightedDeltaEnricher<Double> delta;
-    YamlRollingTimeWindowMeanEnricher<Double> averager;
-    
-    ConfidenceQualifiedNumber average;
-    SubscriptionContext subscription;
-    
-    @SuppressWarnings("unchecked")
-    @BeforeMethod
-    public void before() {
-        app = new AbstractApplication() {};
-        Entities.startManagement(app);
-        producer = app.addChild(EntitySpec.create(BasicEntity.class));
-
-        intSensor = new BasicAttributeSensor<Integer>(Integer.class, "int sensor");
-        deltaSensor = new BasicAttributeSensor<Double>(Double.class, "delta sensor");
-        avgSensor = new BasicAttributeSensor<Double>(Double.class, "avg sensor");
-            
-        delta = producer.addEnricher(EnricherSpec.create(YamlTimeWeightedDeltaEnricher.class)
-                .configure(YamlTimeWeightedDeltaEnricher.PRODUCER, producer)
-                .configure(YamlTimeWeightedDeltaEnricher.SOURCE_SENSOR, intSensor)
-                .configure(YamlTimeWeightedDeltaEnricher.TARGET_SENSOR, deltaSensor));
-
-        averager = producer.addEnricher(EnricherSpec.create(YamlRollingTimeWindowMeanEnricher.class)
-                .configure(YamlRollingTimeWindowMeanEnricher.PRODUCER, producer)
-                .configure(YamlRollingTimeWindowMeanEnricher.SOURCE_SENSOR, deltaSensor)
-                .configure(YamlRollingTimeWindowMeanEnricher.TARGET_SENSOR, avgSensor)
-                .configure(YamlRollingTimeWindowMeanEnricher.WINDOW_DURATION, timePeriod));
-    }
-
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        if (app != null) Entities.destroyAll(app.getManagementContext());
-    }
-        
-    @Test
-    public void testDefaultAverageWhenEmpty() {
-        ConfidenceQualifiedNumber average = averager.getAverage(0, 0);
-        assertEquals(average.value, 0d);
-        assertEquals(average.confidence, 0.0d);
-    }
-    
-    protected BasicSensorEvent<Integer> newIntSensorEvent(int value, long timestamp) {
-        return new BasicSensorEvent<Integer>(intSensor, producer, value, timestamp);
-    }
-    protected BasicSensorEvent<Double> newDeltaSensorEvent(double value, long timestamp) {
-        return new BasicSensorEvent<Double>(deltaSensor, producer, value, timestamp);
-    }
-
-    @Test
-    public void testNoRecentValuesAverage() {
-        averager.onEvent(newDeltaSensorEvent(10, 0));
-        average = averager.getAverage(timePeriod.toMilliseconds()+1000, 0);
-        assertEquals(average.value, 10d);
-        assertEquals(average.confidence, 0d);
-    }
-
-    @Test
-    public void testNoRecentValuesUsesLastForAverage() {
-        averager.onEvent(newDeltaSensorEvent(10, 0));
-        averager.onEvent(newDeltaSensorEvent(20, 10));
-        average = averager.getAverage(timePeriod.toMilliseconds()+1000, 0);
-        assertEquals(average.value, 20d);
-        assertEquals(average.confidence, 0d);
-    }
-
-    @Test
-    public void testSingleValueTimeAverage() {
-        averager.onEvent(newDeltaSensorEvent(10, 1000));
-        average = averager.getAverage(1000, 0);
-        assertEquals(average.confidence, 0d);
-    }
-
-    @Test
-    public void testTwoValueAverageForPeriod() {
-        averager.onEvent(newDeltaSensorEvent(10, 1000));
-        averager.onEvent(newDeltaSensorEvent(10, 2000));
-        average = averager.getAverage(2000, 0);
-        assertEquals(average.value, 10 /1d);
-        assertEquals(average.confidence, 1d);
-    }
-
-    @Test
-    public void testMonospacedAverage() {
-        averager.onEvent(newDeltaSensorEvent(10, 1000));
-        averager.onEvent(newDeltaSensorEvent(20, 1250));
-        averager.onEvent(newDeltaSensorEvent(30, 1500));
-        averager.onEvent(newDeltaSensorEvent(40, 1750));
-        averager.onEvent(newDeltaSensorEvent(50, 2000));
-        average = averager.getAverage(2000, 0);
-        assertEquals(average.value, (20+30+40+50)/4d);
-        assertEquals(average.confidence, 1d);
-    }
-
-    @Test
-    public void testWeightedAverage() {
-        averager.onEvent(newDeltaSensorEvent(10, 1000));
-        averager.onEvent(newDeltaSensorEvent(20, 1100));
-        averager.onEvent(newDeltaSensorEvent(30, 1300));
-        averager.onEvent(newDeltaSensorEvent(40, 1600));
-        averager.onEvent(newDeltaSensorEvent(50, 2000));
-        
-        average = averager.getAverage(2000, 0);
-        assertEquals(average.value, (20*0.1d)+(30*0.2d)+(40*0.3d)+(50*0.4d));
-        assertEquals(average.confidence, 1d);
-    }
-
-    @Test
-    public void testConfidenceDecay() {
-        averager.onEvent(newDeltaSensorEvent(10, 1000));
-        averager.onEvent(newDeltaSensorEvent(20, 1250));
-        averager.onEvent(newDeltaSensorEvent(30, 1500));
-        averager.onEvent(newDeltaSensorEvent(40, 1750));
-        averager.onEvent(newDeltaSensorEvent(50, 2000));
-
-        average = averager.getAverage(2250, 0);
-        assertEquals(average.value, (30+40+50)/3d);
-        assertEquals(average.confidence, 0.75d);
-        average = averager.getAverage(2500, 0);
-        assertEquals(average.value, (40+50)/2d);
-        assertEquals(average.confidence, 0.5d);
-        average = averager.getAverage(2750, 0);
-        assertEquals(average.value, 50d);
-        assertEquals(average.confidence, 0.25d);
-        average = averager.getAverage(3000, 0);
-        assertEquals(average.value, 50d);
-        assertEquals(average.confidence, 0d);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/sensor/enricher/YamlTimeWeightedDeltaEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/enricher/YamlTimeWeightedDeltaEnricherTest.java b/core/src/test/java/org/apache/brooklyn/sensor/enricher/YamlTimeWeightedDeltaEnricherTest.java
deleted file mode 100644
index 5b98168..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/enricher/YamlTimeWeightedDeltaEnricherTest.java
+++ /dev/null
@@ -1,107 +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 org.testng.Assert.assertEquals;
-
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.mgmt.SubscriptionContext;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.api.sensor.EnricherSpec;
-import org.apache.brooklyn.core.entity.AbstractApplication;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
-import org.apache.brooklyn.core.sensor.BasicSensorEvent;
-import org.apache.brooklyn.entity.stock.BasicEntity;
-import org.apache.brooklyn.sensor.enricher.YamlTimeWeightedDeltaEnricher;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-public class YamlTimeWeightedDeltaEnricherTest {
-    
-    AbstractApplication app;
-    
-    BasicEntity producer;
-
-    AttributeSensor<Integer> intSensor;
-    AttributeSensor<Double> avgSensor, deltaSensor;
-    SubscriptionContext subscription;
-    
-    @BeforeMethod
-    public void before() {
-        app = new AbstractApplication() {};
-        Entities.startManagement(app);
-        producer = app.addChild(EntitySpec.create(BasicEntity.class));
-
-        intSensor = new BasicAttributeSensor<Integer>(Integer.class, "int sensor");
-        deltaSensor = new BasicAttributeSensor<Double>(Double.class, "delta sensor");
-    }
-
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        if (app != null) Entities.destroyAll(app.getManagementContext());
-    }
-    
-    @Test
-    public void testMonospaceTimeWeightedDeltaEnricher() {
-        @SuppressWarnings("unchecked")
-        YamlTimeWeightedDeltaEnricher<Integer> delta = producer.addEnricher(EnricherSpec.create(YamlTimeWeightedDeltaEnricher.class)
-            .configure(YamlTimeWeightedDeltaEnricher.PRODUCER, producer)
-            .configure(YamlTimeWeightedDeltaEnricher.SOURCE_SENSOR, intSensor)
-            .configure(YamlTimeWeightedDeltaEnricher.TARGET_SENSOR, deltaSensor));
-        
-        delta.onEvent(newIntSensorEvent(0, 0));
-        assertEquals(producer.getAttribute(deltaSensor), null);
-        delta.onEvent(newIntSensorEvent(0, 1000));
-        assertEquals(producer.getAttribute(deltaSensor), 0d);
-        delta.onEvent(newIntSensorEvent(1, 2000));
-        assertEquals(producer.getAttribute(deltaSensor), 1d);
-        delta.onEvent(newIntSensorEvent(3, 3000));
-        assertEquals(producer.getAttribute(deltaSensor), 2d);
-        delta.onEvent(newIntSensorEvent(8, 4000));
-        assertEquals(producer.getAttribute(deltaSensor), 5d);
-    }
-    
-    protected BasicSensorEvent<Integer> newIntSensorEvent(int value, long timestamp) {
-        return new BasicSensorEvent<Integer>(intSensor, producer, value, timestamp);
-    }
-    
-    @Test
-    public void testVariableTimeWeightedDeltaEnricher() {
-        @SuppressWarnings("unchecked")
-        YamlTimeWeightedDeltaEnricher<Integer> delta = producer.addEnricher(EnricherSpec.create(YamlTimeWeightedDeltaEnricher.class)
-            .configure(YamlTimeWeightedDeltaEnricher.PRODUCER, producer)
-            .configure(YamlTimeWeightedDeltaEnricher.SOURCE_SENSOR, intSensor)
-            .configure(YamlTimeWeightedDeltaEnricher.TARGET_SENSOR, deltaSensor));
-        
-        delta.onEvent(newIntSensorEvent(0, 0));
-        delta.onEvent(newIntSensorEvent(0, 2000));
-        assertEquals(producer.getAttribute(deltaSensor), 0d);
-        delta.onEvent(newIntSensorEvent(3, 5000));
-        assertEquals(producer.getAttribute(deltaSensor), 1d);
-        delta.onEvent(newIntSensorEvent(7, 7000));
-        assertEquals(producer.getAttribute(deltaSensor), 2d);
-        delta.onEvent(newIntSensorEvent(12, 7500));
-        assertEquals(producer.getAttribute(deltaSensor), 10d);
-        delta.onEvent(newIntSensorEvent(15, 9500));
-        assertEquals(producer.getAttribute(deltaSensor), 1.5d);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/ResilientMongoDbApp.java
----------------------------------------------------------------------
diff --git a/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/ResilientMongoDbApp.java b/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/ResilientMongoDbApp.java
index 24622c0..6b43e7d 100644
--- a/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/ResilientMongoDbApp.java
+++ b/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/ResilientMongoDbApp.java
@@ -30,6 +30,7 @@ import org.apache.brooklyn.api.sensor.SensorEventListener;
 import org.apache.brooklyn.core.entity.AbstractApplication;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.StartableApplication;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.group.DynamicCluster;
 import org.apache.brooklyn.entity.nosql.mongodb.MongoDBReplicaSet;
 import org.apache.brooklyn.entity.nosql.mongodb.MongoDBServer;
@@ -38,7 +39,6 @@ import org.apache.brooklyn.launcher.BrooklynLauncher;
 import org.apache.brooklyn.policy.ha.ServiceFailureDetector;
 import org.apache.brooklyn.policy.ha.ServiceReplacer;
 import org.apache.brooklyn.policy.ha.ServiceRestarter;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.CommandLineUtil;
 
 import com.google.common.collect.Lists;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExample.java
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExample.java b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExample.java
index 6c56b5f..0d224bd 100644
--- a/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExample.java
+++ b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExample.java
@@ -35,6 +35,7 @@ import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.StartableApplication;
 import org.apache.brooklyn.core.location.PortRanges;
 import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster;
 import org.apache.brooklyn.entity.webapp.DynamicWebAppCluster;
 import org.apache.brooklyn.entity.webapp.JavaWebAppService;
@@ -43,7 +44,6 @@ import org.apache.brooklyn.entity.webapp.WebAppServiceConstants;
 import org.apache.brooklyn.launcher.BrooklynLauncher;
 import org.apache.brooklyn.policy.autoscaling.AutoScalerPolicy;
 import org.apache.brooklyn.policy.enricher.HttpLatencyDetector;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.CommandLineUtil;
 
 import com.google.common.collect.ImmutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExampleApp.java
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExampleApp.java b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExampleApp.java
index ed8a987..b1d373b 100644
--- a/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExampleApp.java
+++ b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExampleApp.java
@@ -37,6 +37,7 @@ import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.StartableApplication;
 import org.apache.brooklyn.core.location.PortRanges;
 import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster;
 import org.apache.brooklyn.entity.webapp.DynamicWebAppCluster;
 import org.apache.brooklyn.entity.webapp.JavaWebAppService;
@@ -48,7 +49,6 @@ import org.apache.brooklyn.entity.java.JavaEntityMethods;
 import org.apache.brooklyn.launcher.BrooklynLauncher;
 import org.apache.brooklyn.policy.autoscaling.AutoScalerPolicy;
 import org.apache.brooklyn.policy.enricher.HttpLatencyDetector;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.CommandLineUtil;
 import org.apache.brooklyn.util.core.BrooklynMavenArtifacts;
 import org.apache.brooklyn.util.core.ResourceUtils;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/examples/simple-web-cluster/src/test/java/org/apache/brooklyn/demo/RebindWebClusterDatabaseExampleAppIntegrationTest.java
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/test/java/org/apache/brooklyn/demo/RebindWebClusterDatabaseExampleAppIntegrationTest.java b/examples/simple-web-cluster/src/test/java/org/apache/brooklyn/demo/RebindWebClusterDatabaseExampleAppIntegrationTest.java
index 40fd821..128e6cf 100644
--- a/examples/simple-web-cluster/src/test/java/org/apache/brooklyn/demo/RebindWebClusterDatabaseExampleAppIntegrationTest.java
+++ b/examples/simple-web-cluster/src/test/java/org/apache/brooklyn/demo/RebindWebClusterDatabaseExampleAppIntegrationTest.java
@@ -26,11 +26,11 @@ import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.StartableApplication;
 import org.apache.brooklyn.core.mgmt.rebind.RebindOptions;
 import org.apache.brooklyn.core.mgmt.rebind.RebindTestFixture;
+import org.apache.brooklyn.enricher.stock.Propagator;
 import org.apache.brooklyn.entity.proxy.nginx.NginxController;
 import org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster;
 import org.apache.brooklyn.entity.webapp.DynamicWebAppCluster;
 import org.apache.brooklyn.entity.webapp.tomcat.Tomcat8Server;
-import org.apache.brooklyn.sensor.enricher.Propagator;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.test.HttpTestUtils;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/policy/src/main/java/org/apache/brooklyn/policy/enricher/DeltaEnricher.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/enricher/DeltaEnricher.java b/policy/src/main/java/org/apache/brooklyn/policy/enricher/DeltaEnricher.java
index 64b789d..784c709 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/enricher/DeltaEnricher.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/enricher/DeltaEnricher.java
@@ -25,7 +25,7 @@ import org.apache.brooklyn.api.entity.Entity;
 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.sensor.enricher.AbstractTransformingEnricher;
+import org.apache.brooklyn.enricher.stock.AbstractTransformingEnricher;
 import org.apache.brooklyn.util.core.flags.TypeCoercions;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/policy/src/main/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetector.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetector.java b/policy/src/main/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetector.java
index c5d7415..58fda00 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetector.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetector.java
@@ -34,12 +34,12 @@ import org.apache.brooklyn.api.sensor.SensorEvent;
 import org.apache.brooklyn.api.sensor.SensorEventListener;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.feed.http.HttpFeed;
 import org.apache.brooklyn.feed.http.HttpPollConfig;
 import org.apache.brooklyn.feed.http.HttpValueFunctions;
-import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.javalang.AtomicReferences;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/policy/src/main/java/org/apache/brooklyn/policy/enricher/RollingMeanEnricher.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/enricher/RollingMeanEnricher.java b/policy/src/main/java/org/apache/brooklyn/policy/enricher/RollingMeanEnricher.java
index f5ffc35..40243a1 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/enricher/RollingMeanEnricher.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/enricher/RollingMeanEnricher.java
@@ -24,7 +24,7 @@ import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.SensorEvent;
-import org.apache.brooklyn.sensor.enricher.AbstractTypeTransformingEnricher;
+import org.apache.brooklyn.enricher.stock.AbstractTypeTransformingEnricher;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.javalang.JavaClassNames;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/policy/src/main/java/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricher.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricher.java b/policy/src/main/java/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricher.java
index e91e2a8..ae6d637 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricher.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricher.java
@@ -27,8 +27,8 @@ import org.apache.brooklyn.api.sensor.Sensor;
 import org.apache.brooklyn.api.sensor.SensorEvent;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.sensor.enricher.AbstractTypeTransformingEnricher;
-import org.apache.brooklyn.sensor.enricher.YamlRollingTimeWindowMeanEnricher;
+import org.apache.brooklyn.enricher.stock.AbstractTypeTransformingEnricher;
+import org.apache.brooklyn.enricher.stock.YamlRollingTimeWindowMeanEnricher;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.javalang.JavaClassNames;
 import org.apache.brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/policy/src/main/java/org/apache/brooklyn/policy/enricher/TimeFractionDeltaEnricher.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/enricher/TimeFractionDeltaEnricher.java b/policy/src/main/java/org/apache/brooklyn/policy/enricher/TimeFractionDeltaEnricher.java
index ec325fd..3906b7b 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/enricher/TimeFractionDeltaEnricher.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/enricher/TimeFractionDeltaEnricher.java
@@ -27,7 +27,7 @@ import org.apache.brooklyn.api.entity.Entity;
 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.sensor.enricher.AbstractTypeTransformingEnricher;
+import org.apache.brooklyn.enricher.stock.AbstractTypeTransformingEnricher;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.javalang.JavaClassNames;
 import org.apache.brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/policy/src/main/java/org/apache/brooklyn/policy/enricher/TimeWeightedDeltaEnricher.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/enricher/TimeWeightedDeltaEnricher.java b/policy/src/main/java/org/apache/brooklyn/policy/enricher/TimeWeightedDeltaEnricher.java
index 433c415..7eb4460 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/enricher/TimeWeightedDeltaEnricher.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/enricher/TimeWeightedDeltaEnricher.java
@@ -24,8 +24,8 @@ import org.apache.brooklyn.api.entity.Entity;
 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.sensor.enricher.AbstractTypeTransformingEnricher;
-import org.apache.brooklyn.sensor.enricher.YamlTimeWeightedDeltaEnricher;
+import org.apache.brooklyn.enricher.stock.AbstractTypeTransformingEnricher;
+import org.apache.brooklyn.enricher.stock.YamlTimeWeightedDeltaEnricher;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.groovy.GroovyJavaMethods;
 import org.apache.brooklyn.util.javalang.JavaClassNames;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynClusterImpl.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynClusterImpl.java
index bbe5bf2..8a9543d 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynClusterImpl.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynClusterImpl.java
@@ -27,12 +27,12 @@ import org.apache.brooklyn.core.entity.EntityFunctions;
 import org.apache.brooklyn.core.entity.EntityPredicates;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceProblemsLogic;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.brooklynnode.effector.BrooklynClusterUpgradeEffectorBody;
 import org.apache.brooklyn.entity.brooklynnode.effector.SelectMasterEffectorBody;
 import org.apache.brooklyn.entity.group.DynamicClusterImpl;
 import org.apache.brooklyn.feed.function.FunctionFeed;
 import org.apache.brooklyn.feed.function.FunctionPollConfig;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.time.Duration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
index 02f5965..df9651e 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
@@ -45,6 +45,7 @@ import org.apache.brooklyn.core.feed.ConfigToAttributes;
 import org.apache.brooklyn.core.location.Locations;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.brooklynnode.EntityHttpClient.ResponseCodePredicates;
 import org.apache.brooklyn.entity.brooklynnode.effector.BrooklynNodeUpgradeEffectorBody;
 import org.apache.brooklyn.entity.brooklynnode.effector.SetHighAvailabilityModeEffectorBody;
@@ -59,7 +60,6 @@ import org.apache.brooklyn.feed.http.JsonFunctions;
 import org.apache.http.HttpStatus;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.collections.Jsonya;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.config.ConfigBag;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcessImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcessImpl.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcessImpl.java
index b67780b..f4e02c4 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcessImpl.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcessImpl.java
@@ -41,6 +41,7 @@ import org.apache.brooklyn.api.sensor.EnricherSpec;
 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.enricher.AbstractEnricher;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
@@ -56,7 +57,6 @@ import org.apache.brooklyn.feed.function.FunctionPollConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.config.ConfigBag;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/base/src/main/java/org/apache/brooklyn/entity/system_service/SystemServiceEnricher.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/system_service/SystemServiceEnricher.java b/software/base/src/main/java/org/apache/brooklyn/entity/system_service/SystemServiceEnricher.java
index 6470a4b..4b8c5f5 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/system_service/SystemServiceEnricher.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/system_service/SystemServiceEnricher.java
@@ -28,13 +28,13 @@ import org.apache.brooklyn.api.sensor.Enricher;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.effector.EffectorTasks;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags.WrappedStream;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
 import org.apache.brooklyn.util.core.task.BasicExecutionManager;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
 import org.apache.brooklyn.util.core.task.TaskBuilder;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeImpl.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeImpl.java
index f78ddba..40f0989 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeImpl.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeImpl.java
@@ -20,13 +20,13 @@ package org.apache.brooklyn.entity.database.crate;
 
 import org.apache.brooklyn.core.config.render.RendererHints;
 import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.java.JavaAppUtils;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
 import org.apache.brooklyn.feed.http.HttpFeed;
 import org.apache.brooklyn.feed.http.HttpPollConfig;
 import org.apache.brooklyn.feed.http.HttpValueFunctions;
 import org.apache.brooklyn.feed.jmx.JmxFeed;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.guava.Functionals;
 
 public class CrateNodeImpl extends SoftwareProcessImpl implements CrateNode{

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterImpl.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterImpl.java
index d6527ca..9a444fd 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterImpl.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterImpl.java
@@ -38,10 +38,10 @@ import org.apache.brooklyn.core.entity.EntityPredicates;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceNotUpLogic;
 import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.group.DynamicClusterImpl;
 import org.apache.brooklyn.feed.function.FunctionFeed;
 import org.apache.brooklyn.feed.function.FunctionPollConfig;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.collections.CollectionFunctionals;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
 import org.apache.brooklyn.util.core.task.TaskBuilder;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaClusterImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaClusterImpl.java
index ceb4422..3daa097 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaClusterImpl.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaClusterImpl.java
@@ -28,11 +28,11 @@ import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.feed.ConfigToAttributes;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.entity.group.DynamicCluster;
 import org.apache.brooklyn.entity.zookeeper.ZooKeeperNode;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.exceptions.CompoundRuntimeException;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormDeploymentImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormDeploymentImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormDeploymentImpl.java
index e8faa7b..61d6a4e 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormDeploymentImpl.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormDeploymentImpl.java
@@ -25,12 +25,12 @@ import static org.apache.brooklyn.entity.messaging.storm.Storm.Role.UI;
 
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.entity.group.DynamicCluster;
 import org.apache.brooklyn.entity.stock.BasicStartableImpl;
 import org.apache.brooklyn.entity.zookeeper.ZooKeeperEnsemble;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.core.ResourceUtils;
 
 public class StormDeploymentImpl extends BasicStartableImpl implements StormDeployment {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/network/src/test/java/org/apache/brooklyn/entity/network/bind/BindDnsServerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/network/src/test/java/org/apache/brooklyn/entity/network/bind/BindDnsServerIntegrationTest.java b/software/network/src/test/java/org/apache/brooklyn/entity/network/bind/BindDnsServerIntegrationTest.java
index a87cc9c..2f68059 100644
--- a/software/network/src/test/java/org/apache/brooklyn/entity/network/bind/BindDnsServerIntegrationTest.java
+++ b/software/network/src/test/java/org/apache/brooklyn/entity/network/bind/BindDnsServerIntegrationTest.java
@@ -31,9 +31,9 @@ import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
 import org.apache.brooklyn.core.mgmt.rebind.RebindOptions;
 import org.apache.brooklyn.core.mgmt.rebind.RebindTestFixture;
 import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.group.DynamicCluster;
 import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/network/src/test/java/org/apache/brooklyn/entity/network/bind/PrefixAndIdEnricher.java
----------------------------------------------------------------------
diff --git a/software/network/src/test/java/org/apache/brooklyn/entity/network/bind/PrefixAndIdEnricher.java b/software/network/src/test/java/org/apache/brooklyn/entity/network/bind/PrefixAndIdEnricher.java
index c32e2ce..9c75ace 100644
--- a/software/network/src/test/java/org/apache/brooklyn/entity/network/bind/PrefixAndIdEnricher.java
+++ b/software/network/src/test/java/org/apache/brooklyn/entity/network/bind/PrefixAndIdEnricher.java
@@ -24,8 +24,8 @@ import org.apache.brooklyn.api.sensor.SensorEvent;
 import org.apache.brooklyn.api.sensor.SensorEventListener;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
 import org.apache.brooklyn.core.sensor.Sensors;
-import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
 
 import com.google.common.reflect.TypeToken;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenterImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenterImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenterImpl.java
index 13df45b..27f83aa 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenterImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenterImpl.java
@@ -42,12 +42,12 @@ import org.apache.brooklyn.core.entity.EntityPredicates;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceNotUpLogic;
 import org.apache.brooklyn.core.location.Machines;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.group.AbstractMembershipTrackingPolicy;
 import org.apache.brooklyn.entity.group.DynamicClusterImpl;
 import org.apache.brooklyn.entity.group.DynamicGroup;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
index 4bff736..3ae6fe9 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
@@ -42,6 +42,7 @@ import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
 import org.apache.brooklyn.core.sensor.DependentConfiguration;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.group.AbstractMembershipTrackingPolicy;
 import org.apache.brooklyn.entity.group.DynamicClusterImpl;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
@@ -51,7 +52,6 @@ import org.apache.brooklyn.feed.http.HttpValueFunctions;
 import org.apache.brooklyn.feed.http.JsonFunctions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.collections.CollectionFunctionals;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.collections.QuorumCheck;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBReplicaSetImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBReplicaSetImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBReplicaSetImpl.java
index 49a1201..399ea91 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBReplicaSetImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBReplicaSetImpl.java
@@ -44,9 +44,9 @@ import org.apache.brooklyn.api.sensor.SensorEventListener;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.group.AbstractMembershipTrackingPolicy;
 import org.apache.brooklyn.entity.group.DynamicClusterImpl;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.text.Strings;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/CoLocatedMongoDBRouterImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/CoLocatedMongoDBRouterImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/CoLocatedMongoDBRouterImpl.java
index e27cb4b..7817dbc 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/CoLocatedMongoDBRouterImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/CoLocatedMongoDBRouterImpl.java
@@ -25,8 +25,8 @@ import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.sensor.DependentConfiguration;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.software.base.SameServerEntityImpl;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 
 import com.google.common.base.Predicates;
 import com.google.common.collect.Iterables;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBShardedDeploymentImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBShardedDeploymentImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBShardedDeploymentImpl.java
index cbebbec..9ef50b9 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBShardedDeploymentImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBShardedDeploymentImpl.java
@@ -35,9 +35,9 @@ import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceNotUpLogic;
 import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.group.AbstractMembershipTrackingPolicy;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisClusterImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisClusterImpl.java
index 838def8..92c7593 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisClusterImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisClusterImpl.java
@@ -30,8 +30,8 @@ import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ComputeServiceIndicatorsFromChildrenAndMembers;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceProblemsLogic;
 import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.collections.QuorumCheck.QuorumChecks;
 import org.apache.brooklyn.util.exceptions.CompoundRuntimeException;
 import org.apache.brooklyn.util.exceptions.Exceptions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakClusterImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakClusterImpl.java
index d3a9b70..5002402 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakClusterImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakClusterImpl.java
@@ -39,9 +39,9 @@ import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceNotUpLogic;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.sensor.DependentConfiguration;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.group.AbstractMembershipTrackingPolicy;
 import org.apache.brooklyn.entity.group.DynamicClusterImpl;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.core.task.Tasks;
 import org.apache.brooklyn.util.time.Duration;
 import org.apache.brooklyn.util.time.Time;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeImpl.java
index 85ac3e8..08773c8 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeImpl.java
@@ -33,12 +33,12 @@ import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
 import org.apache.brooklyn.core.location.cloud.CloudLocationConfig;
 import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
 import org.apache.brooklyn.entity.webapp.WebAppServiceMethods;
 import org.apache.brooklyn.feed.http.HttpFeed;
 import org.apache.brooklyn.feed.http.HttpPollConfig;
 import org.apache.brooklyn.feed.http.HttpValueFunctions;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.guava.Functionals;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxControllerImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxControllerImpl.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxControllerImpl.java
index 7952c91..eadde49 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxControllerImpl.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxControllerImpl.java
@@ -36,6 +36,7 @@ import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceNotUpLogic;
 import org.apache.brooklyn.core.feed.ConfigToAttributes;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.group.AbstractMembershipTrackingPolicy;
 import org.apache.brooklyn.entity.proxy.AbstractControllerImpl;
 import org.apache.brooklyn.entity.proxy.ProxySslConfig;
@@ -43,7 +44,6 @@ import org.apache.brooklyn.entity.proxy.nginx.NginxController.NginxControllerInt
 import org.apache.brooklyn.feed.http.HttpFeed;
 import org.apache.brooklyn.feed.http.HttpPollConfig;
 import org.apache.brooklyn.feed.http.HttpValueFunctions;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.core.file.ArchiveUtils;
 import org.apache.brooklyn.util.core.http.HttpTool;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
index 7ff08a5..3785a47 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
@@ -38,11 +38,11 @@ import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.entity.trait.StartableMethods;
 import org.apache.brooklyn.core.feed.ConfigToAttributes;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.group.DynamicGroupImpl;
 import org.apache.brooklyn.entity.proxy.LoadBalancer;
 import org.apache.brooklyn.entity.proxy.nginx.NginxController;
 import org.apache.brooklyn.entity.webapp.tomcat.TomcatServer;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.QuorumCheck.QuorumChecks;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
index 10d21a1..4bc1fd3 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
@@ -33,9 +33,9 @@ import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.group.DynamicCluster;
 import org.apache.brooklyn.entity.group.DynamicClusterImpl;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.task.DynamicTasks;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppFabricImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppFabricImpl.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppFabricImpl.java
index 38bf6f6..2c9747d 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppFabricImpl.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppFabricImpl.java
@@ -23,8 +23,8 @@ import java.util.List;
 import javax.annotation.Nullable;
 
 import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.group.DynamicFabricImpl;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6ServerImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6ServerImpl.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6ServerImpl.java
index 7c7173b..2d8bc54 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6ServerImpl.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6ServerImpl.java
@@ -24,10 +24,10 @@ import java.util.concurrent.TimeUnit;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcessImpl;
 import org.apache.brooklyn.feed.jmx.JmxAttributePollConfig;
 import org.apache.brooklyn.feed.jmx.JmxFeed;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerImpl.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerImpl.java
index f32d6a0..09f09c1 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerImpl.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerImpl.java
@@ -24,13 +24,13 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.core.config.render.RendererHints;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcessImpl;
 import org.apache.brooklyn.feed.http.HttpFeed;
 import org.apache.brooklyn.feed.http.HttpPollConfig;
 import org.apache.brooklyn.feed.http.HttpValueFunctions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.guava.Functionals;
 
 import com.google.common.base.Functions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jetty/Jetty6ServerImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jetty/Jetty6ServerImpl.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jetty/Jetty6ServerImpl.java
index d264c66..d8f2433 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jetty/Jetty6ServerImpl.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jetty/Jetty6ServerImpl.java
@@ -21,12 +21,12 @@ package org.apache.brooklyn.entity.webapp.jetty;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.java.JavaAppUtils;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcessImpl;
 import org.apache.brooklyn.feed.jmx.JmxAttributePollConfig;
 import org.apache.brooklyn.feed.jmx.JmxFeed;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/usage/archetypes/quickstart/src/brooklyn-sample/src/main/java/com/acme/sample/brooklyn/sample/app/ClusterWebServerDatabaseSample.java
----------------------------------------------------------------------
diff --git a/usage/archetypes/quickstart/src/brooklyn-sample/src/main/java/com/acme/sample/brooklyn/sample/app/ClusterWebServerDatabaseSample.java b/usage/archetypes/quickstart/src/brooklyn-sample/src/main/java/com/acme/sample/brooklyn/sample/app/ClusterWebServerDatabaseSample.java
index bc53541..11d977f 100644
--- a/usage/archetypes/quickstart/src/brooklyn-sample/src/main/java/com/acme/sample/brooklyn/sample/app/ClusterWebServerDatabaseSample.java
+++ b/usage/archetypes/quickstart/src/brooklyn-sample/src/main/java/com/acme/sample/brooklyn/sample/app/ClusterWebServerDatabaseSample.java
@@ -12,6 +12,8 @@ import org.apache.brooklyn.core.entity.AbstractApplication;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.PortRanges;
 import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.enricher.stock.SensorPropagatingEnricher;
+import org.apache.brooklyn.enricher.stock.SensorTransformingEnricher;
 import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
 import org.apache.brooklyn.entity.database.mysql.MySqlNode;
 import org.apache.brooklyn.entity.group.DynamicCluster;
@@ -23,8 +25,6 @@ import org.apache.brooklyn.entity.webapp.WebAppService;
 import org.apache.brooklyn.entity.webapp.WebAppServiceConstants;
 import org.apache.brooklyn.policy.autoscaling.AutoScalerPolicy;
 import org.apache.brooklyn.policy.enricher.HttpLatencyDetector;
-import org.apache.brooklyn.sensor.enricher.SensorPropagatingEnricher;
-import org.apache.brooklyn.sensor.enricher.SensorTransformingEnricher;
 import org.apache.brooklyn.util.maven.MavenArtifact;
 import org.apache.brooklyn.util.maven.MavenRetriever;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/EnrichersYamlTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/EnrichersYamlTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/EnrichersYamlTest.java
index 9054088..8f23a44 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/EnrichersYamlTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/EnrichersYamlTest.java
@@ -30,7 +30,7 @@ import org.apache.brooklyn.core.entity.EntityAdjuncts;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.core.test.policy.TestEnricher;
-import org.apache.brooklyn.sensor.enricher.Propagator;
+import org.apache.brooklyn.enricher.stock.Propagator;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/TestReferencingEnricher.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/TestReferencingEnricher.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/TestReferencingEnricher.java
index 4d8a426..8468014 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/TestReferencingEnricher.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/TestReferencingEnricher.java
@@ -21,7 +21,7 @@ package org.apache.brooklyn.camp.brooklyn;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.BasicConfigKey;
-import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
 
 public class TestReferencingEnricher extends AbstractEnricher {
     public static final ConfigKey<Entity> TEST_APPLICATION = new BasicConfigKey<Entity>(Entity.class, "test.reference.app");

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/usage/camp/src/test/resources/test-app-with-enrichers-slightly-simpler.yaml
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/resources/test-app-with-enrichers-slightly-simpler.yaml b/usage/camp/src/test/resources/test-app-with-enrichers-slightly-simpler.yaml
index bc753a5..2b55237 100644
--- a/usage/camp/src/test/resources/test-app-with-enrichers-slightly-simpler.yaml
+++ b/usage/camp/src/test/resources/test-app-with-enrichers-slightly-simpler.yaml
@@ -29,14 +29,14 @@ services:
     $brooklyn:entitySpec:
       type: org.apache.brooklyn.core.test.entity.TestEntity
       brooklyn.enrichers:
-      - type: org.apache.brooklyn.sensor.enricher.Transformer
+      - type: org.apache.brooklyn.enricher.stock.Transformer
         # transform "ip" (which we expect a feed, not shown here, to set) to a URL;
         # you can curl an address string to the sensors/ip endpoint an entity to trigger these enrichers 
         brooklyn.config:
           enricher.sourceSensor: $brooklyn:sensor("ip")
           enricher.targetSensor: $brooklyn:sensor("url")
           enricher.targetValue: $brooklyn:formatString("http://%s/", $brooklyn:attributeWhenReady("ip"))
-      - type: org.apache.brooklyn.sensor.enricher.Propagator
+      - type: org.apache.brooklyn.enricher.stock.Propagator
         # use propagator to duplicate one sensor as another, giving the supplied sensor mapping;
         # the other use of Propagator is where you specify a producer (using $brooklyn:entity(...) as below)
         # from which to take sensors; in that mode you can specify `propagate` as a list of sensors whose names are unchanged,
@@ -45,13 +45,13 @@ services:
           sensorMapping:
             $brooklyn:sensor("url"): $brooklyn:sensor("org.apache.brooklyn.core.entity.Attributes", "main.uri")
   brooklyn.enrichers:
-  - type: org.apache.brooklyn.sensor.enricher.Aggregator
+  - type: org.apache.brooklyn.enricher.stock.Aggregator
     # aggregate `url` sensors from children into a list
     brooklyn.config:
       enricher.sourceSensor: $brooklyn:sensor("url")
       enricher.targetSensor: $brooklyn:sensor("urls.list")
       enricher.aggregating.fromMembers: true
-  - type: org.apache.brooklyn.sensor.enricher.Joiner
+  - type: org.apache.brooklyn.enricher.stock.Joiner
     # create a string from that list, for use e.g. in bash scripts
     brooklyn.config:
       enricher.sourceSensor: $brooklyn:sensor("urls.list")
@@ -59,7 +59,7 @@ services:
       maximum: 2
       # TODO infer uniqueTag, name etc
       uniqueTag: urls.list.comma_separated.max_2
-  - type: org.apache.brooklyn.sensor.enricher.Joiner
+  - type: org.apache.brooklyn.enricher.stock.Joiner
     # pick one uri as the main one to use
     brooklyn.config:
       enricher.sourceSensor: $brooklyn:sensor("urls.list")
@@ -67,7 +67,7 @@ services:
       quote: false
       maximum: 1
 brooklyn.enrichers:
-- type: org.apache.brooklyn.sensor.enricher.Propagator
+- type: org.apache.brooklyn.enricher.stock.Propagator
   # if nothing specified for `propagating` or `sensorMapping` then 
   # Propagator will do all but the usual lifecycle defaults, handy at the root!
   brooklyn.config:

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/usage/camp/src/test/resources/test-webapp-with-averaging-enricher.yaml
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/resources/test-webapp-with-averaging-enricher.yaml b/usage/camp/src/test/resources/test-webapp-with-averaging-enricher.yaml
index 73b8eae..9a508cb 100644
--- a/usage/camp/src/test/resources/test-webapp-with-averaging-enricher.yaml
+++ b/usage/camp/src/test/resources/test-webapp-with-averaging-enricher.yaml
@@ -32,7 +32,7 @@ services:
       type: org.apache.brooklyn.entity.webapp.DynamicWebAppCluster
       id: cluster
       brooklyn.enrichers:
-      - type: org.apache.brooklyn.sensor.enricher.Aggregator
+      - type: org.apache.brooklyn.enricher.stock.Aggregator
         brooklyn.config:
           enricher.sourceSensor: $brooklyn:sensor("my.load")
           enricher.targetSensor: $brooklyn:sensor("my.load.averaged")
@@ -40,7 +40,7 @@ services:
           transformation: average
             
   brooklyn.enrichers:
-  - type: org.apache.brooklyn.sensor.enricher.Propagator
+  - type: org.apache.brooklyn.enricher.stock.Propagator
     brooklyn.config:
       producer: $brooklyn:entity("cluster")
       propagating:

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/usage/cli/src/main/java/org/apache/brooklyn/cli/lister/ClassFinder.java
----------------------------------------------------------------------
diff --git a/usage/cli/src/main/java/org/apache/brooklyn/cli/lister/ClassFinder.java b/usage/cli/src/main/java/org/apache/brooklyn/cli/lister/ClassFinder.java
index bd1bf6d..06c868b 100644
--- a/usage/cli/src/main/java/org/apache/brooklyn/cli/lister/ClassFinder.java
+++ b/usage/cli/src/main/java/org/apache/brooklyn/cli/lister/ClassFinder.java
@@ -31,11 +31,11 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.objs.BrooklynObject;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.sensor.Enricher;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
 import org.apache.brooklyn.core.entity.AbstractApplication;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.policy.AbstractPolicy;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
-import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
 import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.core.javalang.UrlClassLoader;
 import org.apache.brooklyn.util.net.Urls;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedJBoss7ServerImpl.java
----------------------------------------------------------------------
diff --git a/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedJBoss7ServerImpl.java b/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedJBoss7ServerImpl.java
index 05f40ed..eb55d73 100644
--- a/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedJBoss7ServerImpl.java
+++ b/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedJBoss7ServerImpl.java
@@ -25,6 +25,7 @@ import java.util.concurrent.Callable;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.webapp.jboss.JBoss7ServerImpl;
 import org.apache.brooklyn.entity.webapp.jboss.JBoss7SshDriver;
 import org.apache.brooklyn.feed.function.FunctionFeed;
@@ -33,7 +34,6 @@ import org.apache.brooklyn.feed.http.HttpFeed;
 import org.apache.brooklyn.feed.http.HttpPollConfig;
 import org.apache.brooklyn.feed.http.HttpValueFunctions;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.guava.Functionals;
 import org.apache.brooklyn.util.os.Os;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedTheeTierApp.java
----------------------------------------------------------------------
diff --git a/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedTheeTierApp.java b/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedTheeTierApp.java
index 3c191a1..80daba7 100644
--- a/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedTheeTierApp.java
+++ b/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedTheeTierApp.java
@@ -33,6 +33,7 @@ import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.StartableApplication;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.database.mysql.MySqlNode;
 import org.apache.brooklyn.entity.group.DynamicCluster;
 import org.apache.brooklyn.entity.java.JavaEntityMethods;
@@ -46,7 +47,6 @@ import org.apache.brooklyn.entity.webapp.jboss.JBoss7Server;
 import org.apache.brooklyn.launcher.BrooklynLauncher;
 import org.apache.brooklyn.policy.autoscaling.AutoScalerPolicy;
 import org.apache.brooklyn.policy.enricher.HttpLatencyDetector;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.CommandLineUtil;
 import org.apache.brooklyn.util.collections.MutableSet;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/usage/qa/src/test/java/org/apache/brooklyn/qa/longevity/webcluster/SinusoidalLoadGenerator.java
----------------------------------------------------------------------
diff --git a/usage/qa/src/test/java/org/apache/brooklyn/qa/longevity/webcluster/SinusoidalLoadGenerator.java b/usage/qa/src/test/java/org/apache/brooklyn/qa/longevity/webcluster/SinusoidalLoadGenerator.java
index 06b1cad..7559420 100644
--- a/usage/qa/src/test/java/org/apache/brooklyn/qa/longevity/webcluster/SinusoidalLoadGenerator.java
+++ b/usage/qa/src/test/java/org/apache/brooklyn/qa/longevity/webcluster/SinusoidalLoadGenerator.java
@@ -26,7 +26,7 @@ import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/usage/qa/src/test/java/org/apache/brooklyn/qa/longevity/webcluster/WebClusterApp.java
----------------------------------------------------------------------
diff --git a/usage/qa/src/test/java/org/apache/brooklyn/qa/longevity/webcluster/WebClusterApp.java b/usage/qa/src/test/java/org/apache/brooklyn/qa/longevity/webcluster/WebClusterApp.java
index f43cdcb..31f5060 100644
--- a/usage/qa/src/test/java/org/apache/brooklyn/qa/longevity/webcluster/WebClusterApp.java
+++ b/usage/qa/src/test/java/org/apache/brooklyn/qa/longevity/webcluster/WebClusterApp.java
@@ -28,12 +28,12 @@ import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.StartableApplication;
 import org.apache.brooklyn.core.internal.BrooklynProperties;
 import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.proxy.nginx.NginxController;
 import org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster;
 import org.apache.brooklyn.entity.webapp.jboss.JBoss7Server;
 import org.apache.brooklyn.launcher.BrooklynLauncher;
 import org.apache.brooklyn.policy.autoscaling.AutoScalerPolicy;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.CommandLineUtil;
 
 import com.google.common.collect.Lists;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/usage/rest-server/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java
index a36854a..c1f6334 100644
--- a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java
+++ b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java
@@ -59,10 +59,10 @@ import org.apache.brooklyn.core.mgmt.entitlement.Entitlements;
 import org.apache.brooklyn.core.mgmt.entitlement.Entitlements.StringAndArgument;
 import org.apache.brooklyn.core.objs.BrooklynTypes;
 import org.apache.brooklyn.core.policy.AbstractPolicy;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.stock.BasicApplication;
 import org.apache.brooklyn.rest.domain.ApplicationSpec;
 import org.apache.brooklyn.rest.domain.EntitySpec;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.flags.TypeCoercions;
 import org.apache.brooklyn.util.exceptions.Exceptions;


[22/36] incubator-brooklyn git commit: Rename o.a.b.sensor.feed to o.a.b.feed and o.a.b.core.feed

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/feed/shell/ShellFeedIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/feed/shell/ShellFeedIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/feed/shell/ShellFeedIntegrationTest.java
new file mode 100644
index 0000000..9cf568b
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/feed/shell/ShellFeedIntegrationTest.java
@@ -0,0 +1,226 @@
+/*
+ * 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.feed.shell;
+
+import static org.testng.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.entity.EntityInternal.FeedSupport;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.feed.function.FunctionFeedTest;
+import org.apache.brooklyn.feed.shell.ShellFeed;
+import org.apache.brooklyn.feed.shell.ShellFeedIntegrationTest;
+import org.apache.brooklyn.feed.shell.ShellPollConfig;
+import org.apache.brooklyn.feed.ssh.SshPollValue;
+import org.apache.brooklyn.feed.ssh.SshValueFunctions;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.util.stream.Streams;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class ShellFeedIntegrationTest extends BrooklynAppUnitTestSupport {
+
+    private static final Logger log = LoggerFactory.getLogger(ShellFeedIntegrationTest.class);
+    
+    final static AttributeSensor<String> SENSOR_STRING = Sensors.newStringSensor("aString", "");
+    final static AttributeSensor<Integer> SENSOR_INT = Sensors.newIntegerSensor("anInt", "");
+    final static AttributeSensor<Long> SENSOR_LONG = Sensors.newLongSensor("aLong", "");
+
+    private LocalhostMachineProvisioningLocation loc;
+    private EntityLocal entity;
+    private ShellFeed feed;
+    
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        loc = new LocalhostMachineProvisioningLocation();
+        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        app.start(ImmutableList.of(loc));
+    }
+
+    @AfterMethod(alwaysRun=true)
+    @Override
+    public void tearDown() throws Exception {
+        if (feed != null) feed.stop();
+        super.tearDown();
+        if (loc != null) Streams.closeQuietly(loc);
+    }
+    
+    @Test(groups="Integration")
+    public void testReturnsShellExitStatus() throws Exception {
+        feed = ShellFeed.builder()
+                .entity(entity)
+                .poll(new ShellPollConfig<Integer>(SENSOR_INT)
+                        .command("exit 123")
+                        .onFailure(SshValueFunctions.exitStatus()))
+                .build();
+
+        EntityTestUtils.assertAttributeEqualsEventually(entity, SENSOR_INT, 123);
+    }
+    
+    @Test(groups="Integration")
+    public void testFeedDeDupe() throws Exception {
+        testReturnsShellExitStatus();
+        entity.addFeed(feed);
+        log.info("Feed 0 is: "+feed);
+        
+        testReturnsShellExitStatus();
+        log.info("Feed 1 is: "+feed);
+        entity.addFeed(feed);
+                
+        FeedSupport feeds = ((EntityInternal)entity).feeds();
+        Assert.assertEquals(feeds.getFeeds().size(), 1, "Wrong feed count: "+feeds.getFeeds());
+    }
+    
+    // TODO timeout no longer supported; would be nice to have a generic task-timeout feature,
+    // now that the underlying impl uses SystemProcessTaskFactory
+    @Test(enabled=false, groups={"Integration", "WIP"})
+    public void testShellTimesOut() throws Exception {
+        feed = ShellFeed.builder()
+                .entity(entity)
+                .poll(new ShellPollConfig<String>(SENSOR_STRING)
+                        .command("sleep 10")
+                        .timeout(1, TimeUnit.MILLISECONDS)
+                        .onException(new FunctionFeedTest.ToStringFunction()))
+                .build();
+
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                String val = entity.getAttribute(SENSOR_STRING);
+                assertTrue(val != null && val.contains("timed out after 1ms"), "val=" + val);
+            }});
+    }
+    
+    @Test(groups="Integration")
+    public void testShellUsesEnv() throws Exception {
+        feed = ShellFeed.builder()
+                .entity(entity)
+                .poll(new ShellPollConfig<String>(SENSOR_STRING)
+                        .env(ImmutableMap.of("MYENV", "MYVAL"))
+                        .command("echo hello $MYENV")
+                        .onSuccess(SshValueFunctions.stdout()))
+                .build();
+        
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                String val = entity.getAttribute(SENSOR_STRING);
+                assertTrue(val != null && val.contains("hello MYVAL"), "val="+val);
+            }});
+    }
+    
+    @Test(groups="Integration")
+    public void testReturnsShellStdout() throws Exception {
+        feed = ShellFeed.builder()
+                .entity(entity)
+                .poll(new ShellPollConfig<String>(SENSOR_STRING)
+                        .command("echo hello")
+                        .onSuccess(SshValueFunctions.stdout()))
+                .build();
+        
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                String val = entity.getAttribute(SENSOR_STRING);
+                assertTrue(val != null && val.contains("hello"), "val="+val);
+            }});
+    }
+
+    @Test(groups="Integration")
+    public void testReturnsShellStderr() throws Exception {
+        final String cmd = "thiscommanddoesnotexist";
+        
+        feed = ShellFeed.builder()
+                .entity(entity)
+                .poll(new ShellPollConfig<String>(SENSOR_STRING)
+                        .command(cmd)
+                        .onFailure(SshValueFunctions.stderr()))
+                .build();
+        
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                String val = entity.getAttribute(SENSOR_STRING);
+                assertTrue(val != null && val.contains(cmd), "val="+val);
+            }});
+    }
+    
+    @Test(groups="Integration")
+    public void testFailsOnNonZero() throws Exception {
+        feed = ShellFeed.builder()
+                .entity(entity)
+                .poll(new ShellPollConfig<String>(SENSOR_STRING)
+                        .command("exit 123")
+                        .onSuccess(new Function<SshPollValue, String>() {
+                            @Override
+                            public String apply(SshPollValue input) {
+                                return "Exit status (on success) " + input.getExitStatus();
+                            }})
+                        .onFailure(new Function<SshPollValue, String>() {
+                            @Override
+                            public String apply(SshPollValue input) {
+                                return "Exit status (on failure) " + input.getExitStatus();
+                            }}))
+                .build();
+        
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                String val = entity.getAttribute(SENSOR_STRING);
+                assertTrue(val != null && val.contains("Exit status (on failure) 123"), "val="+val);
+            }});
+    }
+    
+    // Example in ShellFeed javadoc
+    @Test(groups="Integration")
+    public void testDiskUsage() throws Exception {
+        feed = ShellFeed.builder()
+                .entity(entity)
+                .poll(new ShellPollConfig<Long>(SENSOR_LONG)
+                        .command("df -P | tail -1")
+                        .onSuccess(new Function<SshPollValue, Long>() {
+                            public Long apply(SshPollValue input) {
+                                String[] parts = input.getStdout().split("[ \\t]+");
+                                System.out.println("input="+input+"; parts="+Arrays.toString(parts));
+                                return Long.parseLong(parts[2]);
+                            }}))
+                .build();
+        
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                Long val = entity.getAttribute(SENSOR_LONG);
+                assertTrue(val != null && val >= 0, "val="+val);
+            }});
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/feed/ssh/SshFeedIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/feed/ssh/SshFeedIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/feed/ssh/SshFeedIntegrationTest.java
new file mode 100644
index 0000000..fa8e2df
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/feed/ssh/SshFeedIntegrationTest.java
@@ -0,0 +1,264 @@
+/*
+ * 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.feed.ssh;
+
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.brooklyn.api.entity.EntityInitializer;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.entity.EntityInternal.FeedSupport;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.feed.ssh.SshFeed;
+import org.apache.brooklyn.feed.ssh.SshFeedIntegrationTest;
+import org.apache.brooklyn.feed.ssh.SshPollConfig;
+import org.apache.brooklyn.feed.ssh.SshPollValue;
+import org.apache.brooklyn.feed.ssh.SshValueFunctions;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.stream.Streams;
+import org.apache.brooklyn.util.text.StringFunctions;
+import org.apache.brooklyn.util.text.StringPredicates;
+import org.apache.brooklyn.util.time.Duration;
+import org.apache.brooklyn.util.time.Time;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicates;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+
+public class SshFeedIntegrationTest extends BrooklynAppUnitTestSupport {
+
+    private static final Logger log = LoggerFactory.getLogger(SshFeedIntegrationTest.class);
+    
+    final static AttributeSensor<String> SENSOR_STRING = Sensors.newStringSensor("aString", "");
+    final static AttributeSensor<Integer> SENSOR_INT = Sensors.newIntegerSensor("aLong", "");
+
+    private LocalhostMachineProvisioningLocation loc;
+    private SshMachineLocation machine;
+    private EntityLocal entity;
+    private SshFeed feed;
+    
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        loc = app.newLocalhostProvisioningLocation();
+        machine = loc.obtain();
+        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        app.start(ImmutableList.of(loc));
+    }
+
+    @AfterMethod(alwaysRun=true)
+    @Override
+    public void tearDown() throws Exception {
+        if (feed != null) feed.stop();
+        super.tearDown();
+        if (loc != null) Streams.closeQuietly(loc);
+    }
+    
+    /** this is one of the most common pattern */
+    @Test(groups="Integration")
+    public void testReturnsSshStdoutAndInfersMachine() throws Exception {
+        final TestEntity entity2 = app.createAndManageChild(EntitySpec.create(TestEntity.class)
+            // inject the machine location, because the app was started with a provisioning location
+            // and TestEntity doesn't provision
+            .location(machine));
+        
+        feed = SshFeed.builder()
+                .entity(entity2)
+                .poll(new SshPollConfig<String>(SENSOR_STRING)
+                        .command("echo hello")
+                        .onSuccess(SshValueFunctions.stdout()))
+                .build();
+        
+        EntityTestUtils.assertAttributeEventuallyNonNull(entity2, SENSOR_STRING);
+        String val = entity2.getAttribute(SENSOR_STRING);
+        Assert.assertTrue(val.contains("hello"), "val="+val);
+        Assert.assertEquals(val.trim(), "hello");
+    }
+
+    @Test(groups="Integration")
+    public void testFeedDeDupe() throws Exception {
+        testReturnsSshStdoutAndInfersMachine();
+        entity.addFeed(feed);
+        log.info("Feed 0 is: "+feed);
+        
+        testReturnsSshStdoutAndInfersMachine();
+        log.info("Feed 1 is: "+feed);
+        entity.addFeed(feed);
+                
+        FeedSupport feeds = ((EntityInternal)entity).feeds();
+        Assert.assertEquals(feeds.getFeeds().size(), 1, "Wrong feed count: "+feeds.getFeeds());
+    }
+    
+    @Test(groups="Integration")
+    public void testReturnsSshExitStatus() throws Exception {
+        feed = SshFeed.builder()
+                .entity(entity)
+                .machine(machine)
+                .poll(new SshPollConfig<Integer>(SENSOR_INT)
+                        .command("exit 123")
+                        .checkSuccess(Predicates.alwaysTrue())
+                        .onSuccess(SshValueFunctions.exitStatus()))
+                .build();
+
+        EntityTestUtils.assertAttributeEqualsEventually(entity, SENSOR_INT, 123);
+    }
+    
+    @Test(groups="Integration")
+    public void testReturnsSshStdout() throws Exception {
+        feed = SshFeed.builder()
+                .entity(entity)
+                .machine(machine)
+                .poll(new SshPollConfig<String>(SENSOR_STRING)
+                        .command("echo hello")
+                        .onSuccess(SshValueFunctions.stdout()))
+                .build();
+        
+        EntityTestUtils.assertAttributeEventually(entity, SENSOR_STRING, 
+            Predicates.compose(Predicates.equalTo("hello"), StringFunctions.trim()));
+    }
+
+    @Test(groups="Integration")
+    public void testReturnsSshStderr() throws Exception {
+        final String cmd = "thiscommanddoesnotexist";
+        
+        feed = SshFeed.builder()
+                .entity(entity)
+                .machine(machine)
+                .poll(new SshPollConfig<String>(SENSOR_STRING)
+                        .command(cmd)
+                        .onFailure(SshValueFunctions.stderr()))
+                .build();
+        
+        EntityTestUtils.assertAttributeEventually(entity, SENSOR_STRING, StringPredicates.containsLiteral(cmd));
+    }
+    
+    @Test(groups="Integration")
+    public void testFailsOnNonZero() throws Exception {
+        feed = SshFeed.builder()
+                .entity(entity)
+                .machine(machine)
+                .poll(new SshPollConfig<String>(SENSOR_STRING)
+                        .command("exit 123")
+                        .onFailure(new Function<SshPollValue, String>() {
+                            @Override
+                            public String apply(SshPollValue input) {
+                                return "Exit status " + input.getExitStatus();
+                            }}))
+                .build();
+        
+        EntityTestUtils.assertAttributeEventually(entity, SENSOR_STRING, StringPredicates.containsLiteral("Exit status 123"));
+    }
+    
+    @Test(groups="Integration")
+    public void testAddedEarly() throws Exception {
+        final TestEntity entity2 = app.addChild(EntitySpec.create(TestEntity.class)
+            .location(machine)
+            .addInitializer(new EntityInitializer() {
+                @Override
+                public void apply(EntityLocal entity) {
+                    SshFeed.builder()
+                        .entity(entity)
+                        .onlyIfServiceUp()
+                        .poll(new SshPollConfig<String>(SENSOR_STRING)
+                            .command("echo hello")
+                            .onSuccess(SshValueFunctions.stdout()))
+                        .build();
+                }
+            }));
+        Time.sleep(Duration.seconds(2));
+        // would be nice to hook in and assert no errors
+        Assert.assertEquals(entity2.getAttribute(SENSOR_STRING), null);
+        Entities.manage(entity2);
+        Time.sleep(Duration.seconds(2));
+        Assert.assertEquals(entity2.getAttribute(SENSOR_STRING), null);
+        entity2.setAttribute(Attributes.SERVICE_UP, true);
+    
+        EntityTestUtils.assertAttributeEventually(entity2, SENSOR_STRING, StringPredicates.containsLiteral("hello"));
+    }
+
+    
+    @Test(groups="Integration")
+    public void testDynamicEnvAndCommandSupplier() throws Exception {
+        final TestEntity entity2 = app.createAndManageChild(EntitySpec.create(TestEntity.class).location(machine));
+        
+        final AtomicInteger count = new AtomicInteger();
+        Supplier<Map<String, String>> envSupplier = new Supplier<Map<String,String>>() {
+            @Override
+            public Map<String, String> get() {
+                return MutableMap.of("COUNT", ""+count.incrementAndGet());
+            }
+        };
+        Supplier<String> cmdSupplier = new Supplier<String>() {
+            @Override
+            public String get() {
+                return "echo count-"+count.incrementAndGet()+"-$COUNT";
+            }
+        };
+        
+        feed = SshFeed.builder()
+                .entity(entity2)
+                .poll(new SshPollConfig<String>(SENSOR_STRING)
+                        .env(envSupplier)
+                        .command(cmdSupplier)
+                        .onSuccess(SshValueFunctions.stdout()))
+                .build();
+        
+        EntityTestUtils.assertAttributeEventuallyNonNull(entity2, SENSOR_STRING);        
+        final String val1 = assertDifferentOneInOutput(entity2);
+        
+        EntityTestUtils.assertAttributeEventually(entity2, SENSOR_STRING, Predicates.not(Predicates.equalTo(val1)));        
+        final String val2 = assertDifferentOneInOutput(entity2);
+        log.info("vals from dynamic sensors are: "+val1.trim()+" and "+val2.trim());
+    }
+
+    private String assertDifferentOneInOutput(final TestEntity entity2) {
+        String val = entity2.getAttribute(SENSOR_STRING);
+        Assert.assertTrue(val.startsWith("count"), "val="+val);
+        try {
+            String[] fields = val.trim().split("-");
+            int field1 = Integer.parseInt(fields[1]); 
+            int field2 = Integer.parseInt(fields[2]);
+            Assert.assertEquals(Math.abs(field2-field1), 1, "expected difference of 1");
+        } catch (Throwable t) {
+            Exceptions.propagateIfFatal(t);
+            Assert.fail("Wrong output from sensor, got '"+val.trim()+"', giving error: "+t);
+        }
+        return val;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/feed/windows/WindowsPerformanceCounterFeedLiveTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/feed/windows/WindowsPerformanceCounterFeedLiveTest.java b/core/src/test/java/org/apache/brooklyn/feed/windows/WindowsPerformanceCounterFeedLiveTest.java
new file mode 100644
index 0000000..421fff4
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/feed/windows/WindowsPerformanceCounterFeedLiveTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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.feed.windows;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.location.MachineLocation;
+import org.apache.brooklyn.api.location.MachineProvisioningLocation;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.feed.windows.WindowsPerformanceCounterFeed;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * WindowsPerformanceCounterFeed Live Test.
+ * <p>
+ * This test is currently disabled. To run, you must configure a location named {@code WindowsLiveTest}
+ * or adapt the {@link #LOCATION_SPEC} below.
+ * <p>
+ * The location must provide Windows nodes that are running an SSH server on port 22. The login credentials must
+ * be either be auto-detectable or configured in brooklyn.properties in the usual fashion.
+ * <p>
+ * Here is an example configuration from brooklyn.properties for a pre-configured Windows VM
+ * running an SSH server with public key authentication:
+ * <pre>
+ * {@code brooklyn.location.named.WindowsLiveTest=byon:(hosts="ec2-xx-xxx-xxx-xx.eu-west-1.compute.amazonaws.com")
+ * brooklyn.location.named.WindowsLiveTest.user=Administrator
+ * brooklyn.location.named.WindowsLiveTest.privateKeyFile = ~/.ssh/id_rsa
+ * brooklyn.location.named.WindowsLiveTest.publicKeyFile = ~/.ssh/id_rsa.pub
+ * }</pre>
+ * The location must by {@code byon} or another primitive type. Unfortunately, it's not possible to
+ * use a jclouds location, as adding a dependency on brooklyn-locations-jclouds would cause a
+ * cyclic dependency.
+ */
+public class WindowsPerformanceCounterFeedLiveTest extends BrooklynAppLiveTestSupport {
+
+    final static AttributeSensor<Double> CPU_IDLE_TIME = Sensors.newDoubleSensor("cpu.idleTime", "");
+    final static AttributeSensor<Integer> TELEPHONE_LINES = Sensors.newIntegerSensor("telephone.lines", "");
+
+    private static final String LOCATION_SPEC = "named:WindowsLiveTest";
+
+    private Location loc;
+    private EntityLocal entity;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        super.setUp();
+        
+        Map<String,?> allFlags = MutableMap.<String,Object>builder()
+                .put("tags", ImmutableList.of(getClass().getName()))
+                .build();
+        MachineProvisioningLocation<? extends MachineLocation> provisioningLocation =
+                (MachineProvisioningLocation<? extends MachineLocation>)
+                        mgmt.getLocationRegistry().resolve(LOCATION_SPEC, allFlags);
+        loc = provisioningLocation.obtain(ImmutableMap.of());
+
+        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        app.start(ImmutableList.of(loc));
+    }
+
+    @Test(groups={"Live","Disabled"}, enabled=false)
+    public void testRetrievesPerformanceCounters() throws Exception {
+        // We can be pretty sure that a Windows instance in the cloud will have zero telephone lines...
+        entity.setAttribute(TELEPHONE_LINES, 42);
+        WindowsPerformanceCounterFeed feed = WindowsPerformanceCounterFeed.builder()
+                .entity(entity)
+                .addSensor("\\Processor(_total)\\% Idle Time", CPU_IDLE_TIME)
+                .addSensor("\\Telephony\\Lines", TELEPHONE_LINES)
+                .build();
+        try {
+            EntityTestUtils.assertAttributeEqualsEventually(entity, TELEPHONE_LINES, 0);
+        } finally {
+            feed.stop();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/feed/windows/WindowsPerformanceCounterFeedTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/feed/windows/WindowsPerformanceCounterFeedTest.java b/core/src/test/java/org/apache/brooklyn/feed/windows/WindowsPerformanceCounterFeedTest.java
new file mode 100644
index 0000000..3f4862b
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/feed/windows/WindowsPerformanceCounterFeedTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.feed.windows;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.feed.windows.WindowsPerformanceCounterFeed;
+import org.apache.brooklyn.feed.windows.WindowsPerformanceCounterPollConfig;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+
+import io.cloudsoft.winrm4j.winrm.WinRmToolResponse;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+public class WindowsPerformanceCounterFeedTest extends BrooklynAppUnitTestSupport {
+
+    private Location loc;
+    private EntityLocal entity;
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        loc = new LocalhostMachineProvisioningLocation();
+        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        app.start(ImmutableList.of(loc));
+    }
+
+    @AfterMethod(alwaysRun=true)
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    private static final Logger log = LoggerFactory.getLogger(WindowsPerformanceCounterFeedTest.class);
+
+    @Test
+    public void testIteratorWithSingleValue() {
+        Iterator<?> iterator = new WindowsPerformanceCounterFeed
+                .PerfCounterValueIterator("\"10/14/2013 15:28:24.406\",\"0.000000\"");
+        assertTrue(iterator.hasNext());
+        assertEquals(iterator.next(), "0.000000");
+        assertFalse(iterator.hasNext());
+    }
+
+    @Test
+    public void testIteratorWithMultipleValues() {
+        Iterator<?> iterator = new WindowsPerformanceCounterFeed
+                .PerfCounterValueIterator("\"10/14/2013 15:35:50.582\",\"8803.000000\",\"405622.000000\"");
+        assertTrue(iterator.hasNext());
+        assertEquals(iterator.next(), "8803.000000");
+        assertTrue(iterator.hasNext());
+        assertEquals(iterator.next(), "405622.000000");
+        assertFalse(iterator.hasNext());
+    }
+
+    @Test
+    public void testSendPerfCountersToSensors() {
+        AttributeSensor<String> stringSensor = Sensors.newStringSensor("foo.bar");
+        AttributeSensor<Integer> integerSensor = Sensors.newIntegerSensor("bar.baz");
+        AttributeSensor<Double> doubleSensor = Sensors.newDoubleSensor("baz.quux");
+
+        Collection<WindowsPerformanceCounterPollConfig<?>> polls = ImmutableSet.<WindowsPerformanceCounterPollConfig<?>>of(
+                new WindowsPerformanceCounterPollConfig(stringSensor).performanceCounterName("\\processor information(_total)\\% processor time"),
+                new WindowsPerformanceCounterPollConfig(integerSensor).performanceCounterName("\\integer.sensor"),
+                new WindowsPerformanceCounterPollConfig(doubleSensor).performanceCounterName("\\double\\sensor\\with\\multiple\\sub\\paths")
+        );
+
+        WindowsPerformanceCounterFeed.SendPerfCountersToSensors sendPerfCountersToSensors = new WindowsPerformanceCounterFeed.SendPerfCountersToSensors(entity, polls);
+
+        assertNull(entity.getAttribute(stringSensor));
+
+        StringBuilder responseBuilder = new StringBuilder();
+        // NOTE: This builds the response in a different order to which they are passed to the SendPerfCountersToSensors constructor
+        // this tests that the values are applied correctly even if the (possibly non-deterministic) order in which
+        // they are returned by the Get-Counter scriptlet is different
+        addMockResponse(responseBuilder, "\\\\machine.name\\double\\sensor\\with\\multiple\\sub\\paths", "3.1415926");
+        addMockResponse(responseBuilder, "\\\\win-lge7uj2blau\\processor information(_total)\\% processor time", "99.9");
+        addMockResponse(responseBuilder, "\\\\machine.name\\integer.sensor", "15");
+
+        sendPerfCountersToSensors.onSuccess(new WinRmToolResponse(responseBuilder.toString(), "", 0));
+
+        EntityTestUtils.assertAttributeEquals(entity, stringSensor, "99.9");
+        EntityTestUtils.assertAttributeEquals(entity, integerSensor, 15);
+        EntityTestUtils.assertAttributeEquals(entity, doubleSensor, 3.1415926);
+    }
+
+    private void addMockResponse(StringBuilder responseBuilder, String path, String value) {
+        responseBuilder.append(path);
+        responseBuilder.append(Strings.repeat(" ", 200 - (path.length() + value.length())));
+        responseBuilder.append(value);
+        responseBuilder.append("\r\n");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/sensor/feed/ConfigToAttributesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/feed/ConfigToAttributesTest.java b/core/src/test/java/org/apache/brooklyn/sensor/feed/ConfigToAttributesTest.java
deleted file mode 100644
index b82aecf..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/feed/ConfigToAttributesTest.java
+++ /dev/null
@@ -1,70 +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.feed;
-
-import static org.testng.Assert.assertEquals;
-
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
-import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
-import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.core.sensor.TemplatedStringAttributeSensorAndConfigKey;
-import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-public class ConfigToAttributesTest {
-
-    private ManagementContextInternal managementContext;
-
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() throws Exception {
-        managementContext = new LocalManagementContext();
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        if (managementContext != null) Entities.destroyAll(managementContext);
-    }
-    
-    @Test
-    public void testApplyTemplatedConfigWithEntity() {
-        TestApplication app = managementContext.getEntityManager().createEntity(EntitySpec.create(TestApplication.class)
-                .configure(TestEntity.CONF_NAME, "myval"));
-        Entities.startManagement(app, managementContext);
-        
-        BasicAttributeSensorAndConfigKey<String> key = new TemplatedStringAttributeSensorAndConfigKey("mykey", "my descr", "${config['test.confName']!'notfound'}");
-        String val = ConfigToAttributes.apply(app, key);
-        assertEquals(app.getAttribute(key), val);
-        assertEquals(val, "myval");
-
-    }
-    
-    @Test
-    public void testApplyTemplatedConfigWithManagementContext() {
-        managementContext.getBrooklynProperties().put(TestEntity.CONF_NAME, "myglobalval");
-        BasicAttributeSensorAndConfigKey<String> key = new TemplatedStringAttributeSensorAndConfigKey("mykey", "my descr", "${config['test.confName']!'notfound'}");
-        String val = ConfigToAttributes.transform(managementContext, key);
-        assertEquals(val, "myglobalval");
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/sensor/feed/PollerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/feed/PollerTest.java b/core/src/test/java/org/apache/brooklyn/sensor/feed/PollerTest.java
deleted file mode 100644
index 3f9c29b..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/feed/PollerTest.java
+++ /dev/null
@@ -1,108 +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.feed;
-
-import static org.testng.Assert.assertTrue;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.feed.PollHandler;
-import org.apache.brooklyn.sensor.feed.Poller;
-import org.apache.brooklyn.test.Asserts;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.task.DynamicTasks;
-import org.apache.brooklyn.util.time.Duration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-public class PollerTest extends BrooklynAppUnitTestSupport {
-
-    private static final Logger LOG = LoggerFactory.getLogger(PollerTest.class);
-
-    private TestEntity entity;
-    private Poller<Integer> poller;
-    
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        poller = new Poller<Integer>(entity, false);
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    @Override
-    public void tearDown() throws Exception {
-        if (poller != null) poller.stop();
-        super.tearDown();
-    }
-    
-    @Test(groups={"Integration", "WIP"}) // because takes > 1 second
-    public void testPollingSubTaskFailsOnceKeepsGoing() throws Exception {
-        final AtomicInteger counter = new AtomicInteger();
-        poller.scheduleAtFixedRate(
-                new Callable<Integer>() {
-                    @Override public Integer call() throws Exception {
-                        int result = counter.incrementAndGet();
-                        if (result % 2 == 0) {
-                            DynamicTasks.queue("in-poll", new Runnable() {
-                                public void run() {
-                                    throw new IllegalStateException("Simulating error in sub-task for poll");
-                                }});
-                        }
-                        return result;
-                    }
-                },
-                new PollHandler<Integer>() {
-                    @Override public boolean checkSuccess(Integer val) {
-                        return true;
-                    }
-                    @Override public void onSuccess(Integer val) {
-                        
-                    }
-                    @Override public void onFailure(Integer val) {
-                    }
-                    @Override
-                    public void onException(Exception exception) {
-                        LOG.info("Exception in test poller", exception);
-                    }
-                    @Override public String getDescription() {
-                        return "mypollhandler";
-                    }
-                }, 
-                new Duration(10, TimeUnit.MILLISECONDS));
-        poller.start();
-        
-        Asserts.succeedsContinually(MutableMap.of("timeout", 2*1000, "period", 500), new Runnable() {
-            int oldCounter = -1;
-            @Override public void run() {
-                assertTrue(counter.get() > oldCounter);
-                oldCounter = counter.get();
-            }
-        });
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/sensor/feed/function/FunctionFeedTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/feed/function/FunctionFeedTest.java b/core/src/test/java/org/apache/brooklyn/sensor/feed/function/FunctionFeedTest.java
deleted file mode 100644
index 71b44b8..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/feed/function/FunctionFeedTest.java
+++ /dev/null
@@ -1,315 +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.feed.function;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNotEquals;
-import static org.testng.Assert.assertTrue;
-
-import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.api.sensor.Feed;
-import org.apache.brooklyn.api.sensor.SensorEvent;
-import org.apache.brooklyn.api.sensor.SensorEventListener;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.core.entity.EntityInternal.FeedSupport;
-import org.apache.brooklyn.core.sensor.Sensors;
-import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.feed.function.FunctionFeed;
-import org.apache.brooklyn.sensor.feed.function.FunctionFeedTest;
-import org.apache.brooklyn.sensor.feed.function.FunctionPollConfig;
-import org.apache.brooklyn.test.Asserts;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
-
-import com.google.common.base.Function;
-import com.google.common.base.Functions;
-import com.google.common.base.Predicates;
-import com.google.common.base.Suppliers;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.common.util.concurrent.Callables;
-
-public class FunctionFeedTest extends BrooklynAppUnitTestSupport {
-
-    private static final Logger log = LoggerFactory.getLogger(FunctionFeedTest.class);
-    
-    final static AttributeSensor<String> SENSOR_STRING = Sensors.newStringSensor("aString", "");
-    final static AttributeSensor<Integer> SENSOR_INT = Sensors.newIntegerSensor("aLong", "");
-
-    private Location loc;
-    private EntityLocal entity;
-    private FunctionFeed feed;
-    
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        loc = new LocalhostMachineProvisioningLocation();
-        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        app.start(ImmutableList.of(loc));
-    }
-
-    @AfterMethod(alwaysRun=true)
-    @Override
-    public void tearDown() throws Exception {
-        if (feed != null) feed.stop();
-        super.tearDown();
-    }
-    
-    @Test
-    public void testPollsFunctionRepeatedlyToSetAttribute() throws Exception {
-        feed = FunctionFeed.builder()
-                .entity(entity)
-                .poll(new FunctionPollConfig<Integer,Integer>(SENSOR_INT)
-                        .period(1)
-                        .callable(new IncrementingCallable())
-                        //.onSuccess((Function<Object,Integer>)(Function)Functions.identity()))
-                        )
-                .build();
-        
-        Asserts.succeedsEventually(new Runnable() {
-            @Override
-            public void run() {
-                Integer val = entity.getAttribute(SENSOR_INT);
-                assertTrue(val != null && val > 2, "val=" + val);
-            }
-        });
-    }
-    
-    @Test
-    public void testFeedDeDupe() throws Exception {
-        testPollsFunctionRepeatedlyToSetAttribute();
-        entity.addFeed(feed);
-        log.info("Feed 0 is: "+feed);
-        Feed feed0 = feed;
-        
-        testPollsFunctionRepeatedlyToSetAttribute();
-        entity.addFeed(feed);
-        log.info("Feed 1 is: "+feed);
-        Feed feed1 = feed;
-        Assert.assertFalse(feed1==feed0);
-
-        FeedSupport feeds = ((EntityInternal)entity).feeds();
-        Assert.assertEquals(feeds.getFeeds().size(), 1, "Wrong feed count: "+feeds.getFeeds());
-
-        // a couple extra checks, compared to the de-dupe test in other *FeedTest classes
-        Feed feedAdded = Iterables.getOnlyElement(feeds.getFeeds());
-        Assert.assertTrue(feedAdded==feed1);
-        Assert.assertFalse(feedAdded==feed0);
-    }
-    
-    @Test
-    public void testFeedDeDupeIgnoresSameObject() throws Exception {
-        testPollsFunctionRepeatedlyToSetAttribute();
-        entity.addFeed(feed);
-        assertFeedIsPolling();
-        entity.addFeed(feed);
-        assertFeedIsPollingContinuously();
-    }
-
-    @Test
-    public void testCallsOnSuccessWithResultOfCallable() throws Exception {
-        feed = FunctionFeed.builder()
-                .entity(entity)
-                .poll(new FunctionPollConfig<Integer, Integer>(SENSOR_INT)
-                        .period(1)
-                        .callable(Callables.returning(123))
-                        .onSuccess(new AddOneFunction()))
-                .build();
-
-        EntityTestUtils.assertAttributeEqualsEventually(entity, SENSOR_INT, 124);
-    }
-    
-    @Test
-    public void testCallsOnExceptionWithExceptionFromCallable() throws Exception {
-        final String errMsg = "my err msg";
-        
-        feed = FunctionFeed.builder()
-                .entity(entity)
-                .poll(new FunctionPollConfig<Object, String>(SENSOR_STRING)
-                        .period(1)
-                        .callable(new ExceptionCallable(errMsg))
-                        .onException(new ToStringFunction()))
-                .build();
-
-        Asserts.succeedsEventually(new Runnable() {
-            @Override
-            public void run() {
-                String val = entity.getAttribute(SENSOR_STRING);
-                assertTrue(val != null && val.contains(errMsg), "val=" + val);
-            }
-        });
-    }
-
-    @Test
-    public void testCallsOnFailureWithResultOfCallable() throws Exception {
-        feed = FunctionFeed.builder()
-                .entity(entity)
-                .poll(new FunctionPollConfig<Integer, Integer>(SENSOR_INT)
-                        .period(1)
-                        .callable(Callables.returning(1))
-                        .checkSuccess(Predicates.alwaysFalse())
-                        .onSuccess(new AddOneFunction())
-                        .onFailure(Functions.constant(-1)))
-                .build();
-
-        EntityTestUtils.assertAttributeEqualsEventually(entity, SENSOR_INT, -1);
-    }
-
-    @Test
-    public void testCallsOnExceptionWhenCheckSuccessIsFalseButNoFailureHandler() throws Exception {
-        feed = FunctionFeed.builder()
-                .entity(entity)
-                .poll(new FunctionPollConfig<Integer, Integer>(SENSOR_INT)
-                        .period(1)
-                        .callable(Callables.returning(1))
-                        .checkSuccess(Predicates.alwaysFalse())
-                        .onSuccess(new AddOneFunction())
-                        .onException(Functions.constant(-1)))
-                .build();
-
-        EntityTestUtils.assertAttributeEqualsEventually(entity, SENSOR_INT, -1);
-    }
-    
-    @Test
-    public void testSharesFunctionWhenMultiplePostProcessors() throws Exception {
-        final IncrementingCallable incrementingCallable = new IncrementingCallable();
-        final List<Integer> ints = new CopyOnWriteArrayList<Integer>();
-        final List<String> strings = new CopyOnWriteArrayList<String>();
-        
-        entity.subscribe(entity, SENSOR_INT, new SensorEventListener<Integer>() {
-                @Override public void onEvent(SensorEvent<Integer> event) {
-                    ints.add(event.getValue());
-                }});
-        entity.subscribe(entity, SENSOR_STRING, new SensorEventListener<String>() {
-                @Override public void onEvent(SensorEvent<String> event) {
-                    strings.add(event.getValue());
-                }});
-        
-        feed = FunctionFeed.builder()
-                .entity(entity)
-                .poll(new FunctionPollConfig<Integer, Integer>(SENSOR_INT)
-                        .period(10)
-                        .callable(incrementingCallable))
-                .poll(new FunctionPollConfig<Integer, String>(SENSOR_STRING)
-                        .period(10)
-                        .callable(incrementingCallable)
-                        .onSuccess(new ToStringFunction()))
-                .build();
-
-        Asserts.succeedsEventually(new Runnable() {
-            @Override
-            public void run() {
-                assertEquals(ints.subList(0, 2), ImmutableList.of(0, 1));
-                assertTrue(strings.size()>=2, "wrong strings list: "+strings);
-                assertEquals(strings.subList(0, 2), ImmutableList.of("0", "1"), "wrong strings list: "+strings);
-            }});
-    }
-    
-    @Test
-    @SuppressWarnings("unused")
-    public void testFunctionPollConfigBuilding() throws Exception {
-        FunctionPollConfig<Integer, Integer> typeFromCallable = FunctionPollConfig.forSensor(SENSOR_INT)
-                .period(1)
-                .callable(Callables.returning(1))
-                .onSuccess(Functions.constant(-1));
-
-        FunctionPollConfig<Integer, Integer> typeFromSupplier = FunctionPollConfig.forSensor(SENSOR_INT)
-                .period(1)
-                .supplier(Suppliers.ofInstance(1))
-                .onSuccess(Functions.constant(-1));
-
-        FunctionPollConfig<Integer, Integer> usingConstructor = new FunctionPollConfig<Integer, Integer>(SENSOR_INT)
-                .period(1)
-                .supplier(Suppliers.ofInstance(1))
-                .onSuccess(Functions.constant(-1));
-
-        FunctionPollConfig<Integer, Integer> usingConstructorWithFailureOrException = new FunctionPollConfig<Integer, Integer>(SENSOR_INT)
-                .period(1)
-                .supplier(Suppliers.ofInstance(1))
-                .onFailureOrException(Functions.<Integer>constant(null));
-    }
-    
-    
-    private void assertFeedIsPolling() {
-        final Integer val = entity.getAttribute(SENSOR_INT);
-        Asserts.succeedsEventually(new Runnable() {
-            @Override
-            public void run() {
-                assertNotEquals(val, entity.getAttribute(SENSOR_INT));
-            }
-        });
-    }
-    
-    private void assertFeedIsPollingContinuously() {
-        Asserts.succeedsContinually(new Runnable() {
-            @Override
-            public void run() {
-                assertFeedIsPolling();
-            }
-        });
-    }
-
-    private static class IncrementingCallable implements Callable<Integer> {
-        private final AtomicInteger next = new AtomicInteger(0);
-        
-        @Override public Integer call() {
-            return next.getAndIncrement();
-        }
-    }
-    
-    private static class AddOneFunction implements Function<Integer, Integer> {
-        @Override public Integer apply(@Nullable Integer input) {
-            return (input != null) ? (input + 1) : null;
-        }
-    }
-    
-    private static class ExceptionCallable implements Callable<Void> {
-        private final String msg;
-        ExceptionCallable(String msg) {
-            this.msg = msg;
-        }
-        @Override public Void call() {
-            throw new RuntimeException(msg);
-        }
-    }
-    
-    public static class ToStringFunction implements Function<Object, String> {
-        @Override public String apply(@Nullable Object input) {
-            return (input != null) ? (input.toString()) : null;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/sensor/feed/http/HttpFeedIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/feed/http/HttpFeedIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/sensor/feed/http/HttpFeedIntegrationTest.java
deleted file mode 100644
index 475490b..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/feed/http/HttpFeedIntegrationTest.java
+++ /dev/null
@@ -1,160 +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.feed.http;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-
-import java.net.URI;
-
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.core.location.PortRanges;
-import org.apache.brooklyn.core.sensor.Sensors;
-import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.core.test.HttpService;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
-import org.apache.brooklyn.test.Asserts;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
-
-import com.google.common.base.Functions;
-import com.google.common.collect.ImmutableList;
-
-public class HttpFeedIntegrationTest extends BrooklynAppUnitTestSupport {
-
-    final static AttributeSensor<String> SENSOR_STRING = Sensors.newStringSensor("aString", "");
-    final static AttributeSensor<Integer> SENSOR_INT = Sensors.newIntegerSensor("aLong", "");
-
-    private HttpService httpService;
-
-    private Location loc;
-    private EntityLocal entity;
-    private HttpFeed feed;
-    
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        loc = new LocalhostMachineProvisioningLocation();
-        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        app.start(ImmutableList.of(loc));
-    }
-
-    @AfterMethod(alwaysRun=true)
-    @Override
-    public void tearDown() throws Exception {
-        if (feed != null) feed.stop();
-        if (httpService != null) httpService.shutdown();
-        super.tearDown();
-    }
-
-    @Test(groups = {"Integration"})
-    public void testPollsAndParsesHttpGetResponseWithSsl() throws Exception {
-        httpService = new HttpService(PortRanges.fromString("9000+"), true).start();
-        URI baseUrl = new URI(httpService.getUrl());
-
-        assertEquals(baseUrl.getScheme(), "https", "baseUrl="+baseUrl);
-        
-        feed = HttpFeed.builder()
-                .entity(entity)
-                .baseUri(baseUrl)
-                .poll(new HttpPollConfig<Integer>(SENSOR_INT)
-                        .period(100)
-                        .onSuccess(HttpValueFunctions.responseCode()))
-                .poll(new HttpPollConfig<String>(SENSOR_STRING)
-                        .period(100)
-                        .onSuccess(HttpValueFunctions.stringContentsFunction()))
-                .build();
-        
-        EntityTestUtils.assertAttributeEqualsEventually(entity, SENSOR_INT, 200);
-        Asserts.succeedsEventually(new Runnable() {
-            public void run() {
-                String val = entity.getAttribute(SENSOR_STRING);
-                assertTrue(val != null && val.contains("Hello, World"), "val="+val);
-            }});
-    }
-
-    @Test(groups = {"Integration"})
-    public void testPollsAndParsesHttpGetResponseWithBasicAuthentication() throws Exception {
-        final String username = "brooklyn";
-        final String password = "hunter2";
-        httpService = new HttpService(PortRanges.fromString("9000+"))
-                .basicAuthentication(username, password)
-                .start();
-        URI baseUrl = new URI(httpService.getUrl());
-        assertEquals(baseUrl.getScheme(), "http", "baseUrl="+baseUrl);
-
-        feed = HttpFeed.builder()
-                .entity(entity)
-                .baseUri(baseUrl)
-                .credentials(username, password)
-                .poll(new HttpPollConfig<Integer>(SENSOR_INT)
-                        .period(100)
-                        .onSuccess(HttpValueFunctions.responseCode()))
-                .poll(new HttpPollConfig<String>(SENSOR_STRING)
-                        .period(100)
-                        .onSuccess(HttpValueFunctions.stringContentsFunction()))
-                .build();
-
-        EntityTestUtils.assertAttributeEqualsEventually(entity, SENSOR_INT, 200);
-        Asserts.succeedsEventually(new Runnable() {
-            public void run() {
-                String val = entity.getAttribute(SENSOR_STRING);
-                assertTrue(val != null && val.contains("Hello, World"), "val="+val);
-            }});
-    }
-
-    @Test(groups = {"Integration"})
-    public void testPollWithInvalidCredentialsFails() throws Exception {
-        httpService = new HttpService(PortRanges.fromString("9000+"))
-                .basicAuthentication("brooklyn", "hunter2")
-                .start();
-
-        feed = HttpFeed.builder()
-                .entity(entity)
-                .baseUri(httpService.getUrl())
-                .credentials("brooklyn", "9876543210")
-                .poll(new HttpPollConfig<Integer>(SENSOR_INT)
-                        .period(100)
-                        .onSuccess(HttpValueFunctions.responseCode())
-                        .onFailure(HttpValueFunctions.responseCode()))
-                .poll(new HttpPollConfig<String>(SENSOR_STRING)
-                        .period(100)
-                        .onSuccess(HttpValueFunctions.stringContentsFunction())
-                        .onException(Functions.constant("Failed!")))
-                .build();
-
-        EntityTestUtils.assertAttributeEqualsEventually(entity, SENSOR_INT, 401);
-        Asserts.succeedsEventually(new Runnable() {
-            public void run() {
-                String val = entity.getAttribute(SENSOR_STRING);
-                assertTrue(val != null && val.equals("Failed!"), "val=" + val);
-            }
-        });
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/sensor/feed/http/HttpFeedTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/feed/http/HttpFeedTest.java b/core/src/test/java/org/apache/brooklyn/sensor/feed/http/HttpFeedTest.java
deleted file mode 100644
index f04c855..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/feed/http/HttpFeedTest.java
+++ /dev/null
@@ -1,392 +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.feed.http;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-
-import java.net.URL;
-import java.util.List;
-import java.util.concurrent.Callable;
-
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.EntityFunctions;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.core.entity.EntityInternal.FeedSupport;
-import org.apache.brooklyn.core.sensor.Sensors;
-import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.feed.FeedConfig;
-import org.apache.brooklyn.sensor.feed.PollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
-import org.apache.brooklyn.test.Asserts;
-import org.apache.brooklyn.util.collections.MutableList;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.http.BetterMockWebServer;
-import org.apache.brooklyn.util.core.http.HttpToolResponse;
-import org.apache.brooklyn.util.guava.Functionals;
-import org.apache.brooklyn.util.net.Networking;
-import org.apache.brooklyn.util.time.Duration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Function;
-import com.google.common.base.Functions;
-import com.google.common.base.Predicates;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-import com.google.mockwebserver.MockResponse;
-import com.google.mockwebserver.SocketPolicy;
-
-public class HttpFeedTest extends BrooklynAppUnitTestSupport {
-
-    private static final Logger log = LoggerFactory.getLogger(HttpFeedTest.class);
-    
-    final static AttributeSensor<String> SENSOR_STRING = Sensors.newStringSensor("aString", "");
-    final static AttributeSensor<Integer> SENSOR_INT = Sensors.newIntegerSensor( "aLong", "");
-
-    private static final long TIMEOUT_MS = 10*1000;
-    
-    private BetterMockWebServer server;
-    private URL baseUrl;
-    
-    private Location loc;
-    private EntityLocal entity;
-    private HttpFeed feed;
-    
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        server = BetterMockWebServer.newInstanceLocalhost();
-        for (int i = 0; i < 100; i++) {
-            server.enqueue(new MockResponse().setResponseCode(200).addHeader("content-type: application/json").setBody("{\"foo\":\"myfoo\"}"));
-        }
-        server.play();
-        baseUrl = server.getUrl("/");
-
-        loc = app.newLocalhostProvisioningLocation();
-        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        app.start(ImmutableList.of(loc));
-    }
-
-    @AfterMethod(alwaysRun=true)
-    @Override
-    public void tearDown() throws Exception {
-        if (feed != null) feed.stop();
-        if (server != null) server.shutdown();
-        feed = null;
-        super.tearDown();
-    }
-    
-    @Test
-    public void testPollsAndParsesHttpGetResponse() throws Exception {
-        feed = HttpFeed.builder()
-                .entity(entity)
-                .baseUrl(baseUrl)
-                .poll(HttpPollConfig.forSensor(SENSOR_INT)
-                        .period(100)
-                        .onSuccess(HttpValueFunctions.responseCode()))
-                .poll(HttpPollConfig.forSensor(SENSOR_STRING)
-                        .period(100)
-                        .onSuccess(HttpValueFunctions.stringContentsFunction()))
-                .build();
-        
-        assertSensorEventually(SENSOR_INT, (Integer)200, TIMEOUT_MS);
-        assertSensorEventually(SENSOR_STRING, "{\"foo\":\"myfoo\"}", TIMEOUT_MS);
-    }
-    
-    @Test
-    public void testFeedDeDupe() throws Exception {
-        testPollsAndParsesHttpGetResponse();
-        entity.addFeed(feed);
-        log.info("Feed 0 is: "+feed);
-        
-        testPollsAndParsesHttpGetResponse();
-        log.info("Feed 1 is: "+feed);
-        entity.addFeed(feed);
-                
-        FeedSupport feeds = ((EntityInternal)entity).feeds();
-        Assert.assertEquals(feeds.getFeeds().size(), 1, "Wrong feed count: "+feeds.getFeeds());
-    }
-    
-    @Test
-    public void testSetsConnectionTimeout() throws Exception {
-        feed = HttpFeed.builder()
-                .entity(entity)
-                .baseUrl(baseUrl)
-                .poll(new HttpPollConfig<Integer>(SENSOR_INT)
-                        .period(100)
-                        .connectionTimeout(Duration.TEN_SECONDS)
-                        .socketTimeout(Duration.TEN_SECONDS)
-                        .onSuccess(HttpValueFunctions.responseCode()))
-                .build();
-        
-        assertSensorEventually(SENSOR_INT, (Integer)200, TIMEOUT_MS);
-    }
-    
-    // TODO How to cause the other end to just freeze (similar to aws-ec2 when securityGroup port is not open)?
-    @Test
-    public void testSetsConnectionTimeoutWhenServerDisconnects() throws Exception {
-        if (server != null) server.shutdown();
-        server = BetterMockWebServer.newInstanceLocalhost();
-        for (int i = 0; i < 100; i++) {
-            server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.DISCONNECT_AT_START));
-        }
-        server.play();
-        baseUrl = server.getUrl("/");
-
-        feed = HttpFeed.builder()
-                .entity(entity)
-                .baseUrl(baseUrl)
-                .poll(new HttpPollConfig<Integer>(SENSOR_INT)
-                        .period(100)
-                        .connectionTimeout(Duration.TEN_SECONDS)
-                        .socketTimeout(Duration.TEN_SECONDS)
-                        .onSuccess(HttpValueFunctions.responseCode())
-                        .onException(Functions.constant(-1)))
-                .build();
-        
-        assertSensorEventually(SENSOR_INT, -1, TIMEOUT_MS);
-    }
-    
-    
-    @Test
-    public void testPollsAndParsesHttpPostResponse() throws Exception {
-        feed = HttpFeed.builder()
-                .entity(entity)
-                .baseUrl(baseUrl)
-                .poll(new HttpPollConfig<Integer>(SENSOR_INT)
-                        .method("post")
-                        .period(100)
-                        .onSuccess(HttpValueFunctions.responseCode()))
-                .poll(new HttpPollConfig<String>(SENSOR_STRING)
-                        .method("post")
-                        .period(100)
-                        .onSuccess(HttpValueFunctions.stringContentsFunction()))
-                .build();
-        
-        assertSensorEventually(SENSOR_INT, (Integer)200, TIMEOUT_MS);
-        assertSensorEventually(SENSOR_STRING, "{\"foo\":\"myfoo\"}", TIMEOUT_MS);
-    }
-
-    @Test
-    public void testUsesFailureHandlerOn4xx() throws Exception {
-        server = BetterMockWebServer.newInstanceLocalhost();
-        for (int i = 0; i < 100; i++) {
-            server.enqueue(new MockResponse()
-                    .setResponseCode(401)
-                    .setBody("Unauthorised"));
-        }
-        server.play();
-        feed = HttpFeed.builder()
-                .entity(entity)
-                .baseUrl(server.getUrl("/"))
-                .poll(new HttpPollConfig<Integer>(SENSOR_INT)
-                        .period(100)
-                        .onSuccess(HttpValueFunctions.responseCode())
-                        .onFailure(HttpValueFunctions.responseCode()))
-                .poll(new HttpPollConfig<String>(SENSOR_STRING)
-                        .period(100)
-                        .onSuccess(HttpValueFunctions.stringContentsFunction())
-                        .onFailure(Functions.constant("Failed")))
-                .build();
-
-        assertSensorEventually(SENSOR_INT, 401, TIMEOUT_MS);
-        assertSensorEventually(SENSOR_STRING, "Failed", TIMEOUT_MS);
-
-        server.shutdown();
-    }
-
-    @Test
-    public void testUsesExceptionHandlerOn4xxAndNoFailureHandler() throws Exception {
-        server = BetterMockWebServer.newInstanceLocalhost();
-        for (int i = 0; i < 100; i++) {
-            server.enqueue(new MockResponse()
-                    .setResponseCode(401)
-                    .setBody("Unauthorised"));
-        }
-        server.play();
-        feed = HttpFeed.builder()
-                .entity(entity)
-                .baseUrl(server.getUrl("/"))
-                .poll(new HttpPollConfig<Integer>(SENSOR_INT)
-                        .period(100)
-                        .onSuccess(HttpValueFunctions.responseCode())
-                        .onException(Functions.constant(-1)))
-                .build();
-
-        assertSensorEventually(SENSOR_INT, -1, TIMEOUT_MS);
-
-        server.shutdown();
-    }
-
-    @Test(groups="Integration")
-    // marked integration as it takes a wee while
-    public void testSuspendResume() throws Exception {
-        feed = HttpFeed.builder()
-                .entity(entity)
-                .baseUrl(baseUrl)
-                .poll(new HttpPollConfig<Integer>(SENSOR_INT)
-                        .period(100)
-                        .onSuccess(HttpValueFunctions.responseCode()))
-                .poll(new HttpPollConfig<String>(SENSOR_STRING)
-                        .period(100)
-                        .onSuccess(HttpValueFunctions.stringContentsFunction()))
-                .build();
-        assertSensorEventually(SENSOR_INT, (Integer)200, TIMEOUT_MS);
-        feed.suspend();
-        final int countWhenSuspended = server.getRequestCount();
-        
-        Thread.sleep(500);
-        if (server.getRequestCount() > countWhenSuspended+1)
-            Assert.fail("Request count continued to increment while feed was suspended, from "+countWhenSuspended+" to "+server.getRequestCount());
-        
-        feed.resume();
-        Asserts.succeedsEventually(new Runnable() {
-            public void run() {
-                assertTrue(server.getRequestCount() > countWhenSuspended + 1,
-                        "Request count failed to increment when feed was resumed, from " + countWhenSuspended + ", still at " + server.getRequestCount());
-            }
-        });
-    }
-
-    @Test(groups="Integration")
-    // marked integration as it takes a wee while
-    public void testStartSuspended() throws Exception {
-        feed = HttpFeed.builder()
-                .entity(entity)
-                .baseUrl(baseUrl)
-                .poll(HttpPollConfig.forSensor(SENSOR_INT)
-                        .period(100)
-                        .onSuccess(HttpValueFunctions.responseCode()))
-                .poll(HttpPollConfig.forSensor(SENSOR_STRING)
-                        .period(100)
-                        .onSuccess(HttpValueFunctions.stringContentsFunction()))
-                .suspended()
-                .build();
-        Asserts.continually(MutableMap.of("timeout", 500),
-                Entities.attributeSupplier(entity, SENSOR_INT), Predicates.<Integer>equalTo(null));
-        int countWhenSuspended = server.getRequestCount();
-        feed.resume();
-        Asserts.eventually(Entities.attributeSupplier(entity, SENSOR_INT), Predicates.<Integer>equalTo(200));
-        if (server.getRequestCount() <= countWhenSuspended)
-            Assert.fail("Request count failed to increment when feed was resumed, from "+countWhenSuspended+", still at "+server.getRequestCount());
-        log.info("RUN: "+countWhenSuspended+" - "+server.getRequestCount());
-    }
-
-
-    @Test
-    public void testPollsAndParsesHttpErrorResponseLocal() throws Exception {
-        int unboundPort = Networking.nextAvailablePort(10000);
-        feed = HttpFeed.builder()
-                .entity(entity)
-                .baseUri("http://localhost:" + unboundPort + "/path/should/not/exist")
-                .poll(new HttpPollConfig<String>(SENSOR_STRING)
-                        .onSuccess(Functions.constant("success"))
-                        .onFailure(Functions.constant("failure"))
-                        .onException(Functions.constant("error")))
-                .build();
-        
-        assertSensorEventually(SENSOR_STRING, "error", TIMEOUT_MS);
-    }
-
-    @Test
-    public void testPollsMulti() throws Exception {
-        newMultiFeed(baseUrl);
-        assertSensorEventually(SENSOR_INT, (Integer)200, TIMEOUT_MS);
-        assertSensorEventually(SENSOR_STRING, "{\"foo\":\"myfoo\"}", TIMEOUT_MS);
-    }
-
-    // because takes a wee while
-    @SuppressWarnings("rawtypes")
-    @Test(groups="Integration")
-    public void testPollsMultiClearsOnSubsequentFailure() throws Exception {
-        server = BetterMockWebServer.newInstanceLocalhost();
-        for (int i = 0; i < 10; i++) {
-            server.enqueue(new MockResponse()
-                    .setResponseCode(200)
-                    .setBody("Hello World"));
-        }
-        for (int i = 0; i < 10; i++) {
-            server.enqueue(new MockResponse()
-                    .setResponseCode(401)
-                    .setBody("Unauthorised"));
-        }
-        server.play();
-
-        newMultiFeed(server.getUrl("/"));
-        
-        assertSensorEventually(SENSOR_INT, 200, TIMEOUT_MS);
-        assertSensorEventually(SENSOR_STRING, "Hello World", TIMEOUT_MS);
-        
-        assertSensorEventually(SENSOR_INT, -1, TIMEOUT_MS);
-        assertSensorEventually(SENSOR_STRING, null, TIMEOUT_MS);
-        
-        List<String> attrs = Lists.transform(MutableList.copyOf( ((EntityInternal)entity).getAllAttributes().keySet() ),
-            new Function<AttributeSensor,String>() {
-                @Override public String apply(AttributeSensor input) { return input.getName(); } });
-        Assert.assertTrue(!attrs.contains(SENSOR_STRING.getName()), "attrs contained "+SENSOR_STRING);
-        Assert.assertTrue(!attrs.contains(FeedConfig.NO_SENSOR.getName()), "attrs contained "+FeedConfig.NO_SENSOR);
-        
-        server.shutdown();
-    }
-
-    private void newMultiFeed(URL baseUrl) {
-        feed = HttpFeed.builder()
-                .entity(entity)
-                .baseUrl(baseUrl)
-                
-                .poll(HttpPollConfig.forMultiple()
-                    .onSuccess(new Function<HttpToolResponse,Void>() {
-                        public Void apply(HttpToolResponse response) {
-                            entity.setAttribute(SENSOR_INT, response.getResponseCode());
-                            if (response.getResponseCode()==200)
-                                entity.setAttribute(SENSOR_STRING, response.getContentAsString());
-                            return null;
-                        }
-                    })
-                    .onFailureOrException(Functionals.function(EntityFunctions.settingSensorsConstant(entity, MutableMap.<AttributeSensor<?>,Object>of(
-                        SENSOR_INT, -1, 
-                        SENSOR_STRING, PollConfig.REMOVE))))
-                .period(100))
-                .build();
-    }
-    
-
-    private <T> void assertSensorEventually(final AttributeSensor<T> sensor, final T expectedVal, long timeout) {
-        Asserts.succeedsEventually(ImmutableMap.of("timeout", timeout), new Callable<Void>() {
-            public Void call() {
-                assertEquals(entity.getAttribute(sensor), expectedVal);
-                return null;
-            }
-        });
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/sensor/feed/http/HttpValueFunctionsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/feed/http/HttpValueFunctionsTest.java b/core/src/test/java/org/apache/brooklyn/sensor/feed/http/HttpValueFunctionsTest.java
deleted file mode 100644
index 2afcae8..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/feed/http/HttpValueFunctionsTest.java
+++ /dev/null
@@ -1,94 +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.feed.http;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertNull;
-import static org.testng.Assert.assertTrue;
-
-import java.util.NoSuchElementException;
-
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
-import org.apache.brooklyn.util.core.http.HttpToolResponse;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonPrimitive;
-
-public class HttpValueFunctionsTest {
-
-    private int responseCode = 200;
-    private long fullLatency = 1000;
-    private String headerName = "my_header";
-    private String headerVal = "my_header_val";
-    private String bodyKey = "mykey";
-    private String bodyVal = "myvalue";
-    private String body = "{"+bodyKey+":"+bodyVal+"}";
-    private long now;
-    private HttpToolResponse response;
-    
-    @BeforeMethod
-    public void setUp() throws Exception {
-        now = System.currentTimeMillis();
-        response = new HttpToolResponse(responseCode, ImmutableMap.of(headerName, ImmutableList.of(headerVal)), 
-                body.getBytes(), now-fullLatency, fullLatency / 2, fullLatency);
-    }
-    
-    @Test
-    public void testResponseCode() throws Exception {
-        assertEquals(HttpValueFunctions.responseCode().apply(response), Integer.valueOf(responseCode));
-    }
-
-    @Test
-    public void testContainsHeader() throws Exception {
-        assertTrue(HttpValueFunctions.containsHeader(headerName).apply(response));
-        assertFalse(HttpValueFunctions.containsHeader("wrong_header").apply(response));
-    }
-    
-    @Test
-    public void testStringContents() throws Exception {
-        assertEquals(HttpValueFunctions.stringContentsFunction().apply(response), body);
-    }
-
-    @Test
-    public void testJsonContents() throws Exception {
-        JsonElement json = HttpValueFunctions.jsonContents().apply(response);
-        assertTrue(json.isJsonObject());
-        assertEquals(json.getAsJsonObject().entrySet(), ImmutableMap.of(bodyKey, new JsonPrimitive(bodyVal)).entrySet());
-    }
-
-    @Test
-    public void testJsonContentsGettingElement() throws Exception {
-        assertEquals(HttpValueFunctions.jsonContents(bodyKey, String.class).apply(response), bodyVal);
-    }
-
-    @Test(expectedExceptions=NoSuchElementException.class)
-    public void testJsonContentsGettingMissingElement() throws Exception {
-        assertNull(HttpValueFunctions.jsonContents("wrongkey", String.class).apply(response));
-    }
-
-    @Test
-    public void testLatency() throws Exception {
-        assertEquals(HttpValueFunctions.latency().apply(response), Long.valueOf(fullLatency));
-    }
-}


[20/36] incubator-brooklyn git commit: Rename o.a.b.sensor.feed to o.a.b.feed and o.a.b.core.feed

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxFeed.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxFeed.java b/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxFeed.java
new file mode 100644
index 0000000..b3b2994
--- /dev/null
+++ b/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxFeed.java
@@ -0,0 +1,423 @@
+/*
+ * 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.feed.jmx;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.Notification;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.feed.AbstractFeed;
+import org.apache.brooklyn.core.feed.AttributePollHandler;
+import org.apache.brooklyn.core.feed.DelegatingPollHandler;
+import org.apache.brooklyn.core.feed.PollHandler;
+import org.apache.brooklyn.core.feed.Poller;
+import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
+import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
+import com.google.common.reflect.TypeToken;
+
+
+/**
+ * Provides a feed of attribute values, by polling or subscribing over jmx.
+ * 
+ * Example usage (e.g. in an entity that extends {@link SoftwareProcessImpl}):
+ * <pre>
+ * {@code
+ * private JmxFeed feed;
+ * 
+ * //@Override
+ * protected void connectSensors() {
+ *   super.connectSensors();
+ *   
+ *   feed = JmxFeed.builder()
+ *       .entity(this)
+ *       .period(500, TimeUnit.MILLISECONDS)
+ *       .pollAttribute(new JmxAttributePollConfig<Integer>(ERROR_COUNT)
+ *           .objectName(requestProcessorMbeanName)
+ *           .attributeName("errorCount"))
+ *       .pollAttribute(new JmxAttributePollConfig<Boolean>(SERVICE_UP)
+ *           .objectName(serverMbeanName)
+ *           .attributeName("Started")
+ *           .onError(Functions.constant(false)))
+ *       .build();
+ * }
+ * 
+ * {@literal @}Override
+ * protected void disconnectSensors() {
+ *   super.disconnectSensors();
+ *   if (feed != null) feed.stop();
+ * }
+ * }
+ * </pre>
+ * 
+ * @author aled
+ */
+public class JmxFeed extends AbstractFeed {
+
+    public static final Logger log = LoggerFactory.getLogger(JmxFeed.class);
+
+    public static final long JMX_CONNECTION_TIMEOUT_MS = 120*1000;
+
+    public static final ConfigKey<JmxHelper> HELPER = ConfigKeys.newConfigKey(JmxHelper.class, "helper");
+    public static final ConfigKey<Boolean> OWN_HELPER = ConfigKeys.newBooleanConfigKey("ownHelper");
+    public static final ConfigKey<String> JMX_URI = ConfigKeys.newStringConfigKey("jmxUri");
+    public static final ConfigKey<Long> JMX_CONNECTION_TIMEOUT = ConfigKeys.newLongConfigKey("jmxConnectionTimeout");
+    
+    @SuppressWarnings("serial")
+    public static final ConfigKey<SetMultimap<String, JmxAttributePollConfig<?>>> ATTRIBUTE_POLLS = ConfigKeys.newConfigKey(
+            new TypeToken<SetMultimap<String, JmxAttributePollConfig<?>>>() {},
+            "attributePolls");
+
+    @SuppressWarnings("serial")
+    public static final ConfigKey<SetMultimap<List<?>, JmxOperationPollConfig<?>>> OPERATION_POLLS = ConfigKeys.newConfigKey(
+            new TypeToken<SetMultimap<List<?>, JmxOperationPollConfig<?>>>() {},
+            "operationPolls");
+
+    @SuppressWarnings("serial")
+    public static final ConfigKey<SetMultimap<NotificationFilter, JmxNotificationSubscriptionConfig<?>>> NOTIFICATION_SUBSCRIPTIONS = ConfigKeys.newConfigKey(
+            new TypeToken<SetMultimap<NotificationFilter, JmxNotificationSubscriptionConfig<?>>>() {},
+            "notificationPolls");
+
+    public static Builder builder() {
+        return new Builder();
+    }
+    
+    public static class Builder {
+        private EntityLocal entity;
+        private JmxHelper helper;
+        private long jmxConnectionTimeout = JMX_CONNECTION_TIMEOUT_MS;
+        private long period = 500;
+        private TimeUnit periodUnits = TimeUnit.MILLISECONDS;
+        private List<JmxAttributePollConfig<?>> attributePolls = Lists.newArrayList();
+        private List<JmxOperationPollConfig<?>> operationPolls = Lists.newArrayList();
+        private List<JmxNotificationSubscriptionConfig<?>> notificationSubscriptions = Lists.newArrayList();
+        private String uniqueTag;
+        private volatile boolean built;
+        
+        public Builder entity(EntityLocal val) {
+            this.entity = val;
+            return this;
+        }
+        public Builder helper(JmxHelper val) {
+            this.helper = val;
+            return this;
+        }
+        public Builder period(Duration duration) {
+            return period(duration.toMilliseconds(), TimeUnit.MILLISECONDS);
+        }
+        public Builder period(long millis) {
+            return period(millis, TimeUnit.MILLISECONDS);
+        }
+        public Builder period(long val, TimeUnit units) {
+            this.period = val;
+            this.periodUnits = units;
+            return this;
+        }
+        public Builder pollAttribute(JmxAttributePollConfig<?> config) {
+            attributePolls.add(config);
+            return this;
+        }
+        public Builder pollOperation(JmxOperationPollConfig<?> config) {
+            operationPolls.add(config);
+            return this;
+        }
+        public Builder subscribeToNotification(JmxNotificationSubscriptionConfig<?> config) {
+            notificationSubscriptions.add(config);
+            return this;
+        }
+        public Builder uniqueTag(String uniqueTag) {
+            this.uniqueTag = uniqueTag;
+            return this;
+        }
+        public JmxFeed build() {
+            built = true;
+            JmxFeed result = new JmxFeed(this);
+            result.setEntity(checkNotNull(entity, "entity"));
+            result.start();
+            return result;
+        }
+        @Override
+        protected void finalize() {
+            if (!built) log.warn("JmxFeed.Builder created, but build() never called");
+        }
+    }
+
+    private final SetMultimap<ObjectName, NotificationListener> notificationListeners = HashMultimap.create();
+
+    /**
+     * For rebind; do not call directly; use builder
+     */
+    public JmxFeed() {
+    }
+
+    protected JmxFeed(Builder builder) {
+        super();
+        if (builder.helper != null) {
+            JmxHelper helper = builder.helper;
+            setConfig(HELPER, helper);
+            setConfig(OWN_HELPER, false);
+            setConfig(JMX_URI, helper.getUrl());
+        }
+        setConfig(JMX_CONNECTION_TIMEOUT, builder.jmxConnectionTimeout);
+        
+        SetMultimap<String, JmxAttributePollConfig<?>> attributePolls = HashMultimap.<String,JmxAttributePollConfig<?>>create();
+        for (JmxAttributePollConfig<?> config : builder.attributePolls) {
+            if (!config.isEnabled()) continue;
+            @SuppressWarnings({ "rawtypes", "unchecked" })
+            JmxAttributePollConfig<?> configCopy = new JmxAttributePollConfig(config);
+            if (configCopy.getPeriod() < 0) configCopy.period(builder.period, builder.periodUnits);
+            attributePolls.put(configCopy.getObjectName().getCanonicalName() + configCopy.getAttributeName(), configCopy);
+        }
+        setConfig(ATTRIBUTE_POLLS, attributePolls);
+        
+        SetMultimap<List<?>, JmxOperationPollConfig<?>> operationPolls = HashMultimap.<List<?>,JmxOperationPollConfig<?>>create();
+        for (JmxOperationPollConfig<?> config : builder.operationPolls) {
+            if (!config.isEnabled()) continue;
+            @SuppressWarnings({ "rawtypes", "unchecked" })
+            JmxOperationPollConfig<?> configCopy = new JmxOperationPollConfig(config);
+            if (configCopy.getPeriod() < 0) configCopy.period(builder.period, builder.periodUnits);
+            operationPolls.put(configCopy.buildOperationIdentity(), configCopy);
+        }
+        setConfig(OPERATION_POLLS, operationPolls);
+        
+        SetMultimap<NotificationFilter, JmxNotificationSubscriptionConfig<?>> notificationSubscriptions = HashMultimap.create();
+        for (JmxNotificationSubscriptionConfig<?> config : builder.notificationSubscriptions) {
+            if (!config.isEnabled()) continue;
+            notificationSubscriptions.put(config.getNotificationFilter(), config);
+        }
+        setConfig(NOTIFICATION_SUBSCRIPTIONS, notificationSubscriptions);
+        initUniqueTag(builder.uniqueTag, attributePolls, operationPolls, notificationSubscriptions);
+    }
+
+    @Override
+    public void setEntity(EntityLocal entity) {
+        if (getConfig(HELPER) == null) {
+            JmxHelper helper = new JmxHelper(entity);
+            setConfig(HELPER, helper);
+            setConfig(OWN_HELPER, true);
+            setConfig(JMX_URI, helper.getUrl());
+        }
+        super.setEntity(entity);
+    }
+    
+    public String getJmxUri() {
+        return getConfig(JMX_URI);
+    }
+    
+    protected JmxHelper getHelper() {
+        return getConfig(HELPER);
+    }
+    
+    @SuppressWarnings("unchecked")
+    protected Poller<Object> getPoller() {
+        return (Poller<Object>) super.getPoller();
+    }
+    
+    @Override
+    protected boolean isConnected() {
+        return super.isConnected() && getHelper().isConnected();
+    }
+    
+    @Override
+    protected void preStart() {
+        /*
+         * All actions on the JmxHelper are done async (through the poller's threading) so we don't 
+         * block on start/rebind if the entity is unreachable 
+         * (without this we get a 120s pause in JmxHelper.connect restarting)
+         */
+        final SetMultimap<NotificationFilter, JmxNotificationSubscriptionConfig<?>> notificationSubscriptions = getConfig(NOTIFICATION_SUBSCRIPTIONS);
+        final SetMultimap<List<?>, JmxOperationPollConfig<?>> operationPolls = getConfig(OPERATION_POLLS);
+        final SetMultimap<String, JmxAttributePollConfig<?>> attributePolls = getConfig(ATTRIBUTE_POLLS);
+        
+        getPoller().submit(new Callable<Void>() {
+               public Void call() {
+                   getHelper().connect(getConfig(JMX_CONNECTION_TIMEOUT));
+                   return null;
+               }
+               @Override public String toString() { return "Connect JMX "+getHelper().getUrl(); }
+           });
+        
+        for (final NotificationFilter filter : notificationSubscriptions.keySet()) {
+            getPoller().submit(new Callable<Void>() {
+                public Void call() {
+                    // TODO Could config.getObjectName have wildcards? Is this code safe?
+                    Set<JmxNotificationSubscriptionConfig<?>> configs = notificationSubscriptions.get(filter);
+                    NotificationListener listener = registerNotificationListener(configs);
+                    ObjectName objectName = Iterables.get(configs, 0).getObjectName();
+                    notificationListeners.put(objectName, listener);
+                    return null;
+                }
+                @Override public String toString() { return "Register JMX notifications: "+notificationSubscriptions.get(filter); }
+            });
+        }
+        
+        // Setup polling of sensors
+        for (final String jmxAttributeName : attributePolls.keys()) {
+            registerAttributePoller(attributePolls.get(jmxAttributeName));
+        }
+        
+        // Setup polling of operations
+        for (final List<?> operationIdentifier : operationPolls.keys()) {
+            registerOperationPoller(operationPolls.get(operationIdentifier));
+        }
+    }
+    
+    @Override
+    protected void preStop() {
+        super.preStop();
+
+        for (Map.Entry<ObjectName, NotificationListener> entry : notificationListeners.entries()) {
+            unregisterNotificationListener(entry.getKey(), entry.getValue());
+        }
+        notificationListeners.clear();
+    }
+    
+    @Override
+    protected void postStop() {
+        super.postStop();
+        JmxHelper helper = getHelper();
+        Boolean ownHelper = getConfig(OWN_HELPER);
+        if (helper != null && ownHelper) helper.terminate();
+    }
+    
+    /**
+     * Registers to poll a jmx-operation for an ObjectName, where all the given configs are for the same ObjectName + operation + parameters.
+     */
+    private void registerOperationPoller(Set<JmxOperationPollConfig<?>> configs) {
+        Set<AttributePollHandler<? super Object>> handlers = Sets.newLinkedHashSet();
+        long minPeriod = Integer.MAX_VALUE;
+        
+        final ObjectName objectName = Iterables.get(configs, 0).getObjectName();
+        final String operationName = Iterables.get(configs, 0).getOperationName();
+        final List<String> signature = Iterables.get(configs, 0).getSignature();
+        final List<?> params = Iterables.get(configs, 0).getParams();
+        
+        for (JmxOperationPollConfig<?> config : configs) {
+            handlers.add(new AttributePollHandler<Object>(config, getEntity(), this));
+            if (config.getPeriod() > 0) minPeriod = Math.min(minPeriod, config.getPeriod());
+        }
+        
+        getPoller().scheduleAtFixedRate(
+                new Callable<Object>() {
+                    public Object call() throws Exception {
+                        if (log.isDebugEnabled()) log.debug("jmx operation polling for {} sensors at {} -> {}", new Object[] {getEntity(), getJmxUri(), operationName});
+                        if (signature.size() == params.size()) {
+                            return getHelper().operation(objectName, operationName, signature, params);
+                        } else {
+                            return getHelper().operation(objectName, operationName, params.toArray());
+                        }
+                    }
+                }, 
+                new DelegatingPollHandler<Object>(handlers), minPeriod);
+    }
+
+    /**
+     * Registers to poll a jmx-attribute for an ObjectName, where all the given configs are for that same ObjectName + attribute.
+     */
+    private void registerAttributePoller(Set<JmxAttributePollConfig<?>> configs) {
+        Set<AttributePollHandler<? super Object>> handlers = Sets.newLinkedHashSet();
+        long minPeriod = Integer.MAX_VALUE;
+        
+        final ObjectName objectName = Iterables.get(configs, 0).getObjectName();
+        final String jmxAttributeName = Iterables.get(configs, 0).getAttributeName();
+        
+        for (JmxAttributePollConfig<?> config : configs) {
+            handlers.add(new AttributePollHandler<Object>(config, getEntity(), this));
+            if (config.getPeriod() > 0) minPeriod = Math.min(minPeriod, config.getPeriod());
+        }
+        
+        // TODO Not good calling this holding the synchronization lock
+        getPoller().scheduleAtFixedRate(
+                new Callable<Object>() {
+                    public Object call() throws Exception {
+                        if (log.isTraceEnabled()) log.trace("jmx attribute polling for {} sensors at {} -> {}", new Object[] {getEntity(), getJmxUri(), jmxAttributeName});
+                        return getHelper().getAttribute(objectName, jmxAttributeName);
+                    }
+                }, 
+                new DelegatingPollHandler<Object>(handlers), minPeriod);
+    }
+
+    /**
+     * Registers to subscribe to notifications for an ObjectName, where all the given configs are for that same ObjectName + filter.
+     */
+    private NotificationListener registerNotificationListener(Set<JmxNotificationSubscriptionConfig<?>> configs) {
+        final List<AttributePollHandler<? super javax.management.Notification>> handlers = Lists.newArrayList();
+
+        final ObjectName objectName = Iterables.get(configs, 0).getObjectName();
+        final NotificationFilter filter = Iterables.get(configs, 0).getNotificationFilter();
+
+        for (final JmxNotificationSubscriptionConfig<?> config : configs) {
+            AttributePollHandler<javax.management.Notification> handler = new AttributePollHandler<javax.management.Notification>(config, getEntity(), this) {
+                @Override protected Object transformValueOnSuccess(javax.management.Notification val) {
+                    if (config.getOnNotification() != null) {
+                        return config.getOnNotification().apply(val);
+                    } else {
+                        Object result = super.transformValueOnSuccess(val);
+                        if (result instanceof javax.management.Notification)
+                            return ((javax.management.Notification)result).getUserData();
+                        return result;
+                    }
+                }
+            };
+            handlers.add(handler);
+        }
+        final PollHandler<javax.management.Notification> compoundHandler = new DelegatingPollHandler<javax.management.Notification>(handlers);
+        
+        NotificationListener listener = new NotificationListener() {
+            @Override public void handleNotification(Notification notification, Object handback) {
+                compoundHandler.onSuccess(notification);
+            }
+        };
+        getHelper().addNotificationListener(objectName, listener, filter);
+        
+        return listener;
+    }
+    
+    private void unregisterNotificationListener(ObjectName objectName, NotificationListener listener) {
+        try {
+            getHelper().removeNotificationListener(objectName, listener);
+        } catch (RuntimeException e) {
+            log.warn("Failed to unregister listener: "+objectName+", "+listener+"; continuing...", e);
+        }
+    }
+    
+    @Override
+    public String toString() {
+        return "JmxFeed["+(getManagementContext()!=null&&getManagementContext().isRunning()?getJmxUri():"mgmt-not-running")+"]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxHelper.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxHelper.java b/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxHelper.java
new file mode 100644
index 0000000..652ac76
--- /dev/null
+++ b/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxHelper.java
@@ -0,0 +1,724 @@
+/*
+ * 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.feed.jmx;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.apache.brooklyn.util.JavaGroovyEquivalents.groovyTruth;
+import groovy.time.TimeDuration;
+
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.JMX;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanServerConnection;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXServiceURL;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.entity.java.JmxSupport;
+import org.apache.brooklyn.entity.java.UsesJmx;
+import org.apache.brooklyn.util.core.crypto.SecureKeys;
+import org.apache.brooklyn.util.crypto.SslTrustUtils;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.exceptions.RuntimeInterruptedException;
+import org.apache.brooklyn.util.jmx.jmxmp.JmxmpAgent;
+import org.apache.brooklyn.util.repeat.Repeater;
+import org.apache.brooklyn.util.time.Duration;
+import org.apache.brooklyn.util.time.Time;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+
+public class JmxHelper {
+
+    private static final Logger LOG = LoggerFactory.getLogger(JmxHelper.class);
+
+    public static final String JMX_URL_FORMAT = "service:jmx:rmi:///jndi/rmi://%s:%d/%s";
+    // first host:port may be ignored, so above is sufficient, but not sure
+    public static final String RMI_JMX_URL_FORMAT = "service:jmx:rmi://%s:%d/jndi/rmi://%s:%d/%s";
+    // jmxmp
+    public static final String JMXMP_URL_FORMAT = "service:jmx:jmxmp://%s:%d";
+    
+    // Tracks the MBeans we have failed to find, with a set keyed off the url
+    private static final Map<String, Set<ObjectName>> notFoundMBeansByUrl = Collections.synchronizedMap(new WeakHashMap<String, Set<ObjectName>>());
+
+    public static final Map<String, String> CLASSES = ImmutableMap.<String,String>builder()
+            .put("Integer", Integer.TYPE.getName())
+            .put("Long", Long.TYPE.getName())
+            .put("Boolean", Boolean.TYPE.getName())
+            .put("Byte", Byte.TYPE.getName())
+            .put("Character", Character.TYPE.getName())
+            .put("Double", Double.TYPE.getName())
+            .put("Float", Float.TYPE.getName())
+            .put("GStringImpl", String.class.getName())
+            .put("LinkedHashMap", Map.class.getName())
+            .put("TreeMap", Map.class.getName())
+            .put("HashMap", Map.class.getName())
+            .put("ConcurrentHashMap", Map.class.getName())
+            .put("TabularDataSupport", TabularData.class.getName())
+            .put("CompositeDataSupport", CompositeData.class.getName())
+            .build();
+
+    /** constructs a JMX URL suitable for connecting to the given entity, being smart about JMX/RMI vs JMXMP */
+    public static String toJmxUrl(EntityLocal entity) {
+        String url = entity.getAttribute(UsesJmx.JMX_URL);
+        if (url != null) {
+            return url;
+        } else {
+            new JmxSupport(entity, null).setJmxUrl();
+            url = entity.getAttribute(UsesJmx.JMX_URL);
+            return Preconditions.checkNotNull(url, "Could not find URL for "+entity);
+        }
+    }
+
+    /** constructs an RMI/JMX URL with the given inputs 
+     * (where the RMI Registry Port should be non-null, and at least one must be non-null) */
+    public static String toRmiJmxUrl(String host, Integer jmxRmiServerPort, Integer rmiRegistryPort, String context) {
+        if (rmiRegistryPort != null && rmiRegistryPort > 0) {
+            if (jmxRmiServerPort!=null && jmxRmiServerPort > 0 && jmxRmiServerPort!=rmiRegistryPort) {
+                // we have an explicit known JMX RMI server port (e.g. because we are using the agent),
+                // distinct from the RMI registry port
+                // (if the ports are the same, it is a short-hand, and don't use this syntax!)
+                return String.format(RMI_JMX_URL_FORMAT, host, jmxRmiServerPort, host, rmiRegistryPort, context);
+            }
+            return String.format(JMX_URL_FORMAT, host, rmiRegistryPort, context);
+        } else if (jmxRmiServerPort!=null && jmxRmiServerPort > 0) {
+            LOG.warn("No RMI registry port set for "+host+"; attempting to use JMX port for RMI lookup");
+            return String.format(JMX_URL_FORMAT, host, jmxRmiServerPort, context);
+        } else {
+            LOG.warn("No RMI/JMX details set for "+host+"; returning null");
+            return null;
+        }
+    }
+
+    /** constructs a JMXMP URL for connecting to the given host and port */
+    public static String toJmxmpUrl(String host, Integer jmxmpPort) {
+        return "service:jmx:jmxmp://"+host+(jmxmpPort!=null ? ":"+jmxmpPort : "");
+    }
+    
+    final EntityLocal entity;
+    final String url;
+    final String user;
+    final String password;
+
+    private volatile transient JMXConnector connector;
+    private volatile transient MBeanServerConnection connection;
+    private transient boolean triedConnecting;
+    private transient boolean failedReconnecting;
+    private transient long failedReconnectingTime;
+    private int minTimeBetweenReconnectAttempts = 1000;
+    private final AtomicBoolean terminated = new AtomicBoolean();
+    
+    // Tracks the MBeans we have failed to find for this JmsHelper's connection URL (so can log just once for each)
+    private final Set<ObjectName> notFoundMBeans;
+
+    public JmxHelper(EntityLocal entity) {
+        this(toJmxUrl(entity), entity, entity.getAttribute(UsesJmx.JMX_USER), entity.getAttribute(UsesJmx.JMX_PASSWORD));
+        
+        if (entity.getAttribute(UsesJmx.JMX_URL) == null) {
+            entity.setAttribute(UsesJmx.JMX_URL, url);
+        }
+    }
+    
+    // TODO split this in to two classes, one for entities, and one entity-neutral
+    // (simplifying set of constructors below)
+    
+    public JmxHelper(String url) {
+        this(url, null, null);
+    }
+
+    public JmxHelper(String url, String user, String password) {
+        this(url, null, user, password);
+    }
+    
+    public JmxHelper(String url, EntityLocal entity, String user, String password) {
+        this.url = url;
+        this.entity = entity;
+        this.user = user;
+        this.password = password;
+
+        synchronized (notFoundMBeansByUrl) {
+            Set<ObjectName> set = notFoundMBeansByUrl.get(url);
+            if (set == null) {
+                set = Collections.synchronizedSet(Collections.newSetFromMap(new WeakHashMap<ObjectName, Boolean>()));
+                notFoundMBeansByUrl.put(url, set);
+            }
+            notFoundMBeans = set;
+        }
+    }
+
+    public void setMinTimeBetweenReconnectAttempts(int val) {
+        minTimeBetweenReconnectAttempts = val;
+    }
+    
+    public String getUrl(){
+        return url;
+    }
+
+    // ============== connection related calls =======================
+
+    //for tesing purposes
+    protected MBeanServerConnection getConnection() {
+        return connection;
+    }
+
+    /**
+     * Checks if the JmxHelper is connected. Returned value could be stale as soon
+     * as it is received.
+     *
+     * This method is thread safe.
+     *
+     * @return true if connected, false otherwise.
+     */
+    public boolean isConnected() {
+        return connection!=null;
+    }
+
+    /**
+     * Reconnects. If it already is connected, it disconnects first.
+     *
+     * @throws IOException
+     */
+    public synchronized void reconnectWithRetryDampened() throws IOException {
+        // If we've already tried reconnecting very recently, don't try again immediately
+        if (failedReconnecting) {
+            long timeSince = (System.currentTimeMillis() - failedReconnectingTime);
+            if (timeSince < minTimeBetweenReconnectAttempts) {
+                String msg = "Not reconnecting to JMX at "+url+" because attempt failed "+Time.makeTimeStringRounded(timeSince)+" ago";
+                throw new IllegalStateException(msg);
+            }
+        }
+        
+        reconnect();
+    }
+    
+    public synchronized void reconnect() throws IOException {
+        disconnect();
+
+        try {
+            connect();
+            failedReconnecting = false;
+        } catch (Exception e) {
+            if (failedReconnecting) {
+                if (LOG.isDebugEnabled()) LOG.debug("unable to re-connect to JMX url (repeated failure): {}: {}", url, e);
+            } else {
+                LOG.debug("unable to re-connect to JMX url {} (rethrowing): {}", url, e);
+                failedReconnecting = true;
+            }
+            failedReconnectingTime = System.currentTimeMillis();
+            throw Throwables.propagate(e);
+        }
+    }
+
+    /** attempts to connect immediately */
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public synchronized void connect() throws IOException {
+        if (terminated.get()) throw new IllegalStateException("JMX Helper "+this+" already terminated");
+        if (connection != null) return;
+
+        triedConnecting = true;
+        if (connector != null) connector.close();
+        JMXServiceURL serviceUrl = new JMXServiceURL(url);
+        Map env = getConnectionEnvVars();
+        try {
+            connector = JMXConnectorFactory.connect(serviceUrl, env);
+        } catch (NullPointerException npe) {
+            //some software -- eg WSO2 -- will throw an NPE exception if the JMX connection can't be created, instead of an IOException.
+            //this is a break of contract with the JMXConnectorFactory.connect method, so this code verifies if the NPE is
+            //thrown by a known offender (wso2) and if so replaces the bad exception by a new IOException.
+            //ideally WSO2 will fix this bug and we can remove this code.
+            boolean thrownByWso2 = npe.getStackTrace()[0].toString().contains("org.wso2.carbon.core.security.CarbonJMXAuthenticator.authenticate");
+            if (thrownByWso2) {
+                throw new IOException("Failed to connect to url "+url+". NullPointerException is thrown, but replaced by an IOException to fix a WSO2 JMX problem", npe);
+            } else {
+                throw npe;
+            }
+        } catch (IOException e) {
+            Exceptions.propagateIfFatal(e);
+            if (terminated.get()) {
+                throw new IllegalStateException("JMX Helper "+this+" already terminated", e);
+            } else {
+                throw e;
+            }
+        }
+        connection = connector.getMBeanServerConnection();
+        
+        if (terminated.get()) {
+            disconnectNow();
+            throw new IllegalStateException("JMX Helper "+this+" already terminated");
+        }
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public Map getConnectionEnvVars() {
+        Map env = new LinkedHashMap();
+        
+        if (groovyTruth(user) && groovyTruth(password)) {
+            String[] creds = new String[] {user, password};
+            env.put(JMXConnector.CREDENTIALS, creds);
+        }
+        
+        if (entity!=null && groovyTruth(entity.getConfig(UsesJmx.JMX_SSL_ENABLED))) {
+            env.put("jmx.remote.profiles", JmxmpAgent.TLS_JMX_REMOTE_PROFILES);
+
+            PrivateKey key = entity.getConfig(UsesJmx.JMX_SSL_ACCESS_KEY);
+            Certificate cert = entity.getConfig(UsesJmx.JMX_SSL_ACCESS_CERT);
+            KeyStore ks = SecureKeys.newKeyStore();
+            try {
+                KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+                if (key!=null) {
+                    ks.setKeyEntry("brooklyn-jmx-access", key, "".toCharArray(), new Certificate[] { cert });
+                }
+                kmf.init(ks, "".toCharArray());
+
+                TrustManager tms = 
+                        // TODO use root cert for trusting server
+                        //trustStore!=null ? SecureKeys.getTrustManager(trustStore) : 
+                        SslTrustUtils.TRUST_ALL;
+
+                SSLContext ctx = SSLContext.getInstance("TLSv1");
+                ctx.init(kmf.getKeyManagers(), new TrustManager[] { tms }, null);
+                SSLSocketFactory ssf = ctx.getSocketFactory(); 
+                env.put(JmxmpAgent.TLS_SOCKET_FACTORY_PROPERTY, ssf); 
+                
+            } catch (Exception e) {
+                LOG.warn("Error setting key "+key+" for "+entity+": "+e, e);
+            }
+        }
+        
+        return env;
+    }
+
+    /**
+     * Continuously attempts to connect for at least the indicated amount of time; or indefinitely if -1. This method
+     * is useful when you are not sure if the system you are trying to connect to already is up and running.
+     *
+     * This method doesn't throw an Exception, but returns true on success, false otherwise.
+     *
+     * TODO: What happens if already connected?
+     *
+     * @param timeoutMs
+     * @return
+     */
+    public boolean connect(long timeoutMs) {
+        if (LOG.isDebugEnabled()) LOG.debug("Connecting to JMX URL: {} ({})", url, ((timeoutMs == -1) ? "indefinitely" : timeoutMs+"ms timeout"));
+        long startMs = System.currentTimeMillis();
+        long endMs = (timeoutMs == -1) ? Long.MAX_VALUE : (startMs + timeoutMs);
+        long currentTime = startMs;
+        Throwable lastError = null;
+        int attempt = 0;
+        while (currentTime <= endMs) {
+            currentTime = System.currentTimeMillis();
+            if (attempt != 0) sleep(100); //sleep 100 to prevent thrashing and facilitate interruption
+            if (LOG.isTraceEnabled()) LOG.trace("trying connection to {} at time {}", url, currentTime);
+
+            try {
+                connect();
+                return true;
+            } catch (Exception e) {
+                Exceptions.propagateIfFatal(e);
+                if (!terminated.get() && shouldRetryOn(e)) {
+                    if (LOG.isDebugEnabled()) LOG.debug("Attempt {} failed connecting to {} ({})", new Object[] {attempt + 1, url, e.getMessage()});
+                    lastError = e;
+                } else {
+                    throw Exceptions.propagate(e);
+                }
+            }
+            attempt++;
+        }
+        LOG.warn("unable to connect to JMX url: "+url, lastError);
+        return false;
+    }
+
+    private boolean shouldRetryOn(Exception e) {
+        // Expect SecurityException, IOException, etc.
+        // But can also see things like javax.naming.ServiceUnavailableException with WSO2 app-servers.
+        // So let's not try to second guess strange behaviours that future entities will exhibit.
+        //
+        // However, if it was our request that was invalid then not worth retrying.
+        
+        if (e instanceof AttributeNotFoundException) return false;
+        if (e instanceof InstanceAlreadyExistsException) return false;
+        if (e instanceof InstanceNotFoundException) return false;
+        if (e instanceof InvalidAttributeValueException) return false;
+        if (e instanceof ListenerNotFoundException) return false;
+        if (e instanceof MalformedObjectNameException) return false;
+        if (e instanceof NotCompliantMBeanException) return false;
+        if (e instanceof InterruptedException) return false;
+        if (e instanceof RuntimeInterruptedException) return false;
+
+        return true;
+    }
+
+    /**
+     * A thread-safe version of {@link #disconnectNow()}.
+     *
+     * This method is threadsafe.
+     */
+    public synchronized void disconnect() {
+        disconnectNow();
+    }
+    
+    /**
+     * Disconnects, preventing subsequent connections to be made. Method doesn't throw an exception.
+     *
+     * Can safely be called if already disconnected.
+     *
+     * This method is not threadsafe, but will thus not block if 
+     * another thread is taking a long time for connections to timeout.
+     * 
+     * Any concurrent requests will likely get an IOException - see
+     * {@linkplain http://docs.oracle.com/javase/7/docs/api/javax/management/remote/JMXConnector.html#close()}.
+     * 
+     */
+    public void terminate() {
+        terminated.set(true);
+        disconnectNow();
+    }
+    
+    protected void disconnectNow() {
+        triedConnecting = false;
+        if (connector != null) {
+            if (LOG.isDebugEnabled()) LOG.debug("Disconnecting from JMX URL {}", url);
+            try {
+                connector.close();
+            } catch (Exception e) {
+                // close attempts to connect to close cleanly; and if it can't, it throws;
+                // often we disconnect as part of shutdown, even if the other side has already stopped --
+                // so swallow exceptions (no situations known where we need a clean closure on the remote side)
+                if (LOG.isDebugEnabled()) LOG.debug("Caught exception disconnecting from JMX at {} ({})", url, e.getMessage());
+                if (LOG.isTraceEnabled()) LOG.trace("Details for exception disconnecting JMX", e);
+            } finally {
+                connector = null;
+                connection = null;
+            }
+        }
+    }
+
+    /**
+     * Gets a usable MBeanServerConnection.
+     *
+     * Method is threadsafe.
+     *
+     * @returns the MBeanServerConnection
+     * @throws IllegalStateException if not connected.
+     */
+    private synchronized MBeanServerConnection getConnectionOrFail() {
+        if (isConnected())
+            return getConnection();
+
+        if (triedConnecting) {
+            throw new IllegalStateException("Failed to connect to JMX at "+url);
+        } else {
+            String msg = "Not connected (and not attempted to connect) to JMX at "+url+
+                    (failedReconnecting ? (" (last reconnect failure at "+ Time.makeDateString(failedReconnectingTime) + ")") : "");
+            throw new IllegalStateException(msg);
+        }
+    }
+
+    private <T> T invokeWithReconnect(Callable<T> task) {
+        try {
+            return task.call();
+        } catch (Exception e) {
+            if (shouldRetryOn(e)) {
+                try {
+                    reconnectWithRetryDampened();
+                    return task.call();
+                } catch (Exception e2) {
+                    throw Throwables.propagate(e2);
+                }
+            } else {
+                throw Throwables.propagate(e);
+            }
+        }
+    }
+
+    // ====================== query related calls =======================================
+
+    /**
+     * Converts from an object name pattern to a real object name, by querying with findMBean; 
+     * if no matching MBean can be found (or if more than one match found) then returns null.
+     * If the supplied object name is not a pattern then just returns that. If the 
+     */
+    public ObjectName toLiteralObjectName(ObjectName objectName) {
+        if (checkNotNull(objectName, "objectName").isPattern()) {
+            ObjectInstance bean = findMBean(objectName);    
+            return (bean != null) ? bean.getObjectName() : null;
+        } else {
+            return objectName;
+        }
+    }
+    
+    public Set<ObjectInstance> findMBeans(final ObjectName objectName) {
+        return invokeWithReconnect(new Callable<Set<ObjectInstance>>() {
+                public Set<ObjectInstance> call() throws Exception {
+                    return getConnectionOrFail().queryMBeans(objectName, null);
+                }});
+    }
+
+    public ObjectInstance findMBean(ObjectName objectName) {
+        Set<ObjectInstance> beans = findMBeans(objectName);
+        if (beans.size() == 1) {
+            notFoundMBeans.remove(objectName);
+            return Iterables.getOnlyElement(beans);
+        } else {
+            boolean changed = notFoundMBeans.add(objectName);
+
+            if (beans.size() > 1) {
+                if (changed) {
+                    LOG.warn("JMX object name query returned {} values for {} at {}; ignoring all",
+                            new Object[] {beans.size(), objectName.getCanonicalName(), url});
+                } else {
+                    if (LOG.isDebugEnabled()) LOG.debug("JMX object name query returned {} values for {} at {} (repeating); ignoring all", 
+                            new Object[] {beans.size(), objectName.getCanonicalName(), url});
+                }
+            } else {
+                if (changed) {
+                    LOG.warn("JMX object {} not found at {}", objectName.getCanonicalName(), url);
+                } else {
+                    if (LOG.isDebugEnabled()) LOG.debug("JMX object {} not found at {} (repeating)", objectName.getCanonicalName(), url);
+                }
+            }
+            return null;
+        }
+    }
+
+    public Set<ObjectInstance> doesMBeanExistsEventually(final ObjectName objectName, Duration timeout) {
+        return doesMBeanExistsEventually(objectName, timeout.toMilliseconds(), TimeUnit.MILLISECONDS);
+    }
+    public Set<ObjectInstance> doesMBeanExistsEventually(final ObjectName objectName, TimeDuration timeout) {
+        return doesMBeanExistsEventually(objectName, timeout.toMilliseconds(), TimeUnit.MILLISECONDS);
+    }
+    
+    public Set<ObjectInstance> doesMBeanExistsEventually(final ObjectName objectName, long timeoutMillis) {
+        return doesMBeanExistsEventually(objectName, timeoutMillis, TimeUnit.MILLISECONDS);
+    }
+    
+    public Set<ObjectInstance> doesMBeanExistsEventually(String objectName, Duration timeout) {
+        return doesMBeanExistsEventually(createObjectName(objectName), timeout);
+    }
+    public Set<ObjectInstance> doesMBeanExistsEventually(String objectName, TimeDuration timeout) {
+        return doesMBeanExistsEventually(createObjectName(objectName), timeout);
+    }
+    
+    public Set<ObjectInstance> doesMBeanExistsEventually(String objectName, long timeout, TimeUnit timeUnit) {
+        return doesMBeanExistsEventually(createObjectName(objectName), timeout, timeUnit);
+    }
+
+    /** returns set of beans found, with retry, empty set if none after timeout */
+    public Set<ObjectInstance> doesMBeanExistsEventually(final ObjectName objectName, long timeout, TimeUnit timeUnit) {
+        final long timeoutMillis = timeUnit.toMillis(timeout);
+        final AtomicReference<Set<ObjectInstance>> beans = new AtomicReference<Set<ObjectInstance>>(ImmutableSet.<ObjectInstance>of());
+        try {
+            Repeater.create("Wait for "+objectName)
+                    .limitTimeTo(timeout, timeUnit)
+                    .every(500, TimeUnit.MILLISECONDS)
+                    .until(new Callable<Boolean>() {
+                            public Boolean call() {
+                                connect(timeoutMillis);
+                                beans.set(findMBeans(objectName));
+                                return !beans.get().isEmpty();
+                            }})
+                    .rethrowException()
+                    .run();
+            return beans.get();
+        } catch (Exception e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    public void assertMBeanExistsEventually(ObjectName objectName, Duration timeout) {
+        assertMBeanExistsEventually(objectName, timeout.toMilliseconds(), TimeUnit.MILLISECONDS);
+    }
+    public void assertMBeanExistsEventually(ObjectName objectName, TimeDuration timeout) {
+        assertMBeanExistsEventually(objectName, timeout.toMilliseconds(), TimeUnit.MILLISECONDS);
+    }
+    
+    public void assertMBeanExistsEventually(ObjectName objectName, long timeoutMillis) {
+        assertMBeanExistsEventually(objectName, timeoutMillis, TimeUnit.MILLISECONDS);
+    }
+    
+    public void assertMBeanExistsEventually(ObjectName objectName, long timeout, TimeUnit timeUnit) {
+        Set<ObjectInstance> beans = doesMBeanExistsEventually(objectName, timeout, timeUnit);
+        if (beans.size() != 1) {
+            throw new IllegalStateException("MBean "+objectName+" not found within "+timeout+
+                    (beans.size() > 1 ? "; found multiple matches: "+beans : ""));
+        }
+    }
+
+    /**
+     * Returns a specific attribute for a JMX {@link ObjectName}.
+     */
+    public Object getAttribute(ObjectName objectName, final String attribute) {
+        final ObjectName realObjectName = toLiteralObjectName(objectName);
+        
+        if (realObjectName != null) {
+            Object result = invokeWithReconnect(new Callable<Object>() {
+                    public Object call() throws Exception {
+                        return getConnectionOrFail().getAttribute(realObjectName, attribute);
+                    }});
+
+            if (LOG.isTraceEnabled()) LOG.trace("From {}, for jmx attribute {}.{}, got value {}", new Object[] {url, objectName.getCanonicalName(), attribute, result});
+            return result;
+        } else {
+            return null;
+        }
+    }
+
+    public void setAttribute(String objectName, String attribute, Object val) {
+        setAttribute(createObjectName(objectName), attribute, val);
+    }
+
+    public void setAttribute(ObjectName objectName, final String attribute, final Object val) {
+        final ObjectName realObjectName = toLiteralObjectName(objectName);
+        
+        if (realObjectName != null) {
+            invokeWithReconnect(new Callable<Void>() {
+                    public Void call() throws Exception {
+                        getConnectionOrFail().setAttribute(realObjectName, new javax.management.Attribute(attribute, val));
+                        return null;
+                    }});
+            if (LOG.isTraceEnabled()) LOG.trace("From {}, for jmx attribute {}.{}, set value {}", new Object[] {url, objectName.getCanonicalName(), attribute, val});
+        } else {
+            if (LOG.isDebugEnabled()) LOG.debug("From {}, cannot set attribute {}.{}, because mbean not found", new Object[] {url, objectName.getCanonicalName(), attribute});
+        }
+    }
+
+    /** @see #operation(ObjectName, String, Object ...) */
+    public Object operation(String objectName, String method, Object... arguments) {
+        return operation(createObjectName(objectName), method, arguments);
+    }
+
+    /**
+     * Executes an operation on a JMX {@link ObjectName}.
+     */
+    public Object operation(ObjectName objectName, final String method, final Object... arguments) {
+        final ObjectName realObjectName = toLiteralObjectName(objectName);
+        final String[] signature = new String[arguments.length];
+        for (int i = 0; i < arguments.length; i++) {
+            Class<?> clazz = arguments[i].getClass();
+            signature[i] = (CLASSES.containsKey(clazz.getSimpleName()) ? CLASSES.get(clazz.getSimpleName()) : clazz.getName());
+        }
+        
+        Object result = invokeWithReconnect(new Callable<Object>() {
+                public Object call() throws Exception {
+                    return getConnectionOrFail().invoke(realObjectName, method, arguments, signature);
+                }});
+
+        if (LOG.isTraceEnabled()) LOG.trace("From {}, for jmx operation {}.{}({}), got value {}", new Object[] {url, realObjectName.getCanonicalName(), method, Arrays.asList(arguments), 
+                result});
+        return result;
+    }
+
+    public void addNotificationListener(String objectName, NotificationListener listener) {
+        addNotificationListener(createObjectName(objectName), listener, null);
+    }
+    
+    public void addNotificationListener(String objectName, NotificationListener listener, NotificationFilter filter) {
+        addNotificationListener(createObjectName(objectName), listener, filter);
+    }
+
+    public void addNotificationListener(ObjectName objectName, NotificationListener listener) {
+        addNotificationListener(objectName, listener, null);
+    }
+    
+    public void addNotificationListener(final ObjectName objectName, final NotificationListener listener, final NotificationFilter filter) {
+        invokeWithReconnect(new Callable<Void>() {
+                public Void call() throws Exception {
+                    getConnectionOrFail().addNotificationListener(objectName, listener, filter, null);
+                    return null;
+                }});
+    }
+
+    public void removeNotificationListener(String objectName, NotificationListener listener) {
+        removeNotificationListener(createObjectName(objectName), listener);
+    }
+
+    public void removeNotificationListener(final ObjectName objectName, final NotificationListener listener) {
+        removeNotificationListener(objectName, listener, null);
+    }
+    
+    public void removeNotificationListener(final ObjectName objectName, final NotificationListener listener, final NotificationFilter filter) {
+        if (isConnected()) invokeWithReconnect(new Callable<Void>() {
+                public Void call() throws Exception {
+                    getConnectionOrFail().removeNotificationListener(objectName, listener, filter, null);
+                    return null;
+                }});
+    }
+
+    public <M> M getProxyObject(String objectName, Class<M> mbeanInterface) {
+        return getProxyObject(createObjectName(objectName), mbeanInterface);
+    }
+
+    public <M> M getProxyObject(ObjectName objectName, Class<M> mbeanInterface) {
+        MBeanServerConnection connection = getConnectionOrFail();
+        return JMX.newMBeanProxy(connection, objectName, mbeanInterface, false);
+    }
+
+    public static ObjectName createObjectName(String name) {
+        try {
+            return new ObjectName(name);
+        } catch (MalformedObjectNameException e) {
+            throw Throwables.propagate(e);
+        }
+    }
+    
+    private static void sleep(long sleepTimeMillis) {
+        try {
+            Thread.sleep(sleepTimeMillis);
+        } catch (InterruptedException e) {
+            throw new RuntimeInterruptedException(e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxNotificationFilters.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxNotificationFilters.java b/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxNotificationFilters.java
new file mode 100644
index 0000000..4b5d3b6
--- /dev/null
+++ b/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxNotificationFilters.java
@@ -0,0 +1,64 @@
+/*
+ * 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.feed.jmx;
+
+import javax.management.Notification;
+import javax.management.NotificationFilter;
+import javax.management.NotificationFilterSupport;
+
+public class JmxNotificationFilters {
+
+    private JmxNotificationFilters() {} // instead use static utility methods
+    
+    /**
+     * Matches the given notification type.
+     * @see {@link NotificationFilterSupport#enableType(String)}
+     */
+    public static NotificationFilter matchesType(String type) {
+        return matchesTypes(type);
+    }
+
+    /**
+     * Matches any of the given notification types.
+     * @see {@link NotificationFilterSupport#enableType(String)}
+     */
+    public static NotificationFilter matchesTypes(String... types) {
+        NotificationFilterSupport result = new NotificationFilterSupport();
+        for (String type : types) {
+            result.enableType(type);
+        }
+        return result;
+    }
+
+    /**
+     * @deprecated since 0.6.0;
+     *             only works if this brooklyn class is on the classpath of the JVM that your 
+     *             subscribing to notifications on (because it tries to push the filter instance
+     *             to that JVM). So of very limited use in real-world java processes to be managed.
+     *             Therefore this will be deleted to avoid people hitting this surprising behaviour.
+     */
+    @SuppressWarnings("serial")
+    public static NotificationFilter matchesTypeRegex(final String typeRegex) {
+        return new NotificationFilter() {
+            @Override public boolean isNotificationEnabled(Notification notif) {
+                return notif.getType().matches(typeRegex);
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxNotificationSubscriptionConfig.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxNotificationSubscriptionConfig.java b/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxNotificationSubscriptionConfig.java
new file mode 100644
index 0000000..844bacb
--- /dev/null
+++ b/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxNotificationSubscriptionConfig.java
@@ -0,0 +1,95 @@
+/*
+ * 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.feed.jmx;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.Notification;
+import javax.management.NotificationFilter;
+import javax.management.ObjectName;
+
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.feed.FeedConfig;
+import org.apache.brooklyn.util.collections.MutableList;
+
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+
+public class JmxNotificationSubscriptionConfig<T> extends FeedConfig<javax.management.Notification, T, JmxNotificationSubscriptionConfig<T>>{
+
+    private ObjectName objectName;
+    private NotificationFilter notificationFilter;
+    private Function<Notification, T> onNotification;
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public JmxNotificationSubscriptionConfig(AttributeSensor<T> sensor) {
+        super(sensor);
+        onSuccess((Function)Functions.identity());
+    }
+
+    public JmxNotificationSubscriptionConfig(JmxNotificationSubscriptionConfig<T> other) {
+        super(other);
+        this.objectName = other.objectName;
+        this.notificationFilter = other.notificationFilter;
+        this.onNotification = other.onNotification;
+    }
+
+    public ObjectName getObjectName() {
+        return objectName;
+    }
+
+    public NotificationFilter getNotificationFilter() {
+        return notificationFilter;
+    }
+    
+    public Function<Notification, T> getOnNotification() {
+        return onNotification;
+    }
+    
+    public JmxNotificationSubscriptionConfig<T> objectName(ObjectName val) {
+        this.objectName = val; return this;
+    }
+    
+    public JmxNotificationSubscriptionConfig<T> objectName(String val) {
+        try {
+            return objectName(new ObjectName(val));
+        } catch (MalformedObjectNameException e) {
+            throw new IllegalArgumentException("Invalid object name ("+val+")", e);
+        }
+    }
+    
+    public JmxNotificationSubscriptionConfig<T> notificationFilter(NotificationFilter val) {
+        this.notificationFilter = val; return this;
+    }
+
+    public JmxNotificationSubscriptionConfig<T> onNotification(Function<Notification,T> val) {
+        this.onNotification = val; return this;
+    }
+
+    @Override
+    protected Object toStringPollSource() {
+        return objectName;
+    }
+
+    @Override
+    protected MutableList<Object> equalsFields() {
+        return super.equalsFields()
+            .appendIfNotNull(notificationFilter).appendIfNotNull(onNotification);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxOperationPollConfig.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxOperationPollConfig.java b/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxOperationPollConfig.java
new file mode 100644
index 0000000..107401d
--- /dev/null
+++ b/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxOperationPollConfig.java
@@ -0,0 +1,121 @@
+/*
+ * 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.feed.jmx;
+
+import java.util.Collections;
+import java.util.List;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.feed.PollConfig;
+
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+public class JmxOperationPollConfig<T> extends PollConfig<Object, T, JmxOperationPollConfig<T>>{
+
+    private ObjectName objectName;
+    private String operationName;
+    private List<String> signature = Collections.emptyList();
+    private List<?> params = Collections.emptyList();
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public JmxOperationPollConfig(AttributeSensor<T> sensor) {
+        super(sensor);
+        onSuccess((Function)Functions.identity());
+    }
+
+    public JmxOperationPollConfig(JmxOperationPollConfig<T> other) {
+        super(other);
+        this.objectName = other.objectName;
+        this.operationName = other.operationName;
+        this.signature = other.signature != null ? ImmutableList.copyOf(other.signature) : null;
+        this.params = other.params != null ? ImmutableList.copyOf(other.params) : null;
+    }
+
+    public ObjectName getObjectName() {
+        return objectName;
+    }
+    
+    public String getOperationName() {
+        return operationName;
+    }
+    
+    public List<String> getSignature() {
+        return signature;
+    }
+    
+    public List<?> getParams() {
+        return params;
+    }
+    
+    public JmxOperationPollConfig<T> objectName(ObjectName val) {
+        this.objectName = val; return this;
+    }
+    
+    public JmxOperationPollConfig<T> objectName(String val) {
+        try {
+            return objectName(new ObjectName(val));
+        } catch (MalformedObjectNameException e) {
+            throw new IllegalArgumentException("Invalid object name ("+val+")", e);
+        }
+    }
+
+    public JmxOperationPollConfig<T> operationName(String val) {
+        this.operationName = val; return this;
+    }
+    
+    public JmxOperationPollConfig<T> operationSignature(List<String> val) {
+        this.signature = val; return this;
+    }
+    
+    public JmxOperationPollConfig<T> operationParams(List<?> val) {
+        this.params = val; return this;
+    }
+
+    public List<?> buildOperationIdentity() {
+        // FIXME Have a build() method for ensuring signature is set, and making class subsequently immutable?
+        return ImmutableList.of(operationName, buildSignature(), params);
+    }
+    
+    private List<String> buildSignature() {
+        if (signature != null && signature.size() == params.size()) {
+            return signature;
+        } else {
+            List<String> derivedSignature = Lists.newLinkedList();
+            for (Object param : params) {
+                Class<?> clazz = (param != null) ? param.getClass() : null;
+                String clazzName = (clazz != null) ? 
+                         (JmxHelper.CLASSES.containsKey(clazz.getSimpleName()) ? 
+                                 JmxHelper.CLASSES.get(clazz.getSimpleName()) : clazz.getName()) : 
+                         Object.class.getName();
+                derivedSignature.add(clazzName);
+            }
+            return derivedSignature;
+        }
+    }
+
+    @Override protected String toStringBaseName() { return "jmx"; }
+    @Override protected String toStringPollSource() { return objectName+":"+operationName+(params!=null ? params : "[]"); }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxValueFunctions.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxValueFunctions.java b/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxValueFunctions.java
new file mode 100644
index 0000000..5741099
--- /dev/null
+++ b/software/base/src/main/java/org/apache/brooklyn/feed/jmx/JmxValueFunctions.java
@@ -0,0 +1,95 @@
+/*
+ * 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.feed.jmx;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Maps;
+
+public class JmxValueFunctions {
+
+    private static final Logger log = LoggerFactory.getLogger(JmxValueFunctions.class);
+    
+    /**
+     * @return a closure that converts a TabularDataSupport to a map.
+     */
+    public static Function<TabularData, Map> tabularDataToMap() {
+        return new Function<TabularData, Map>() {
+            @Override public Map apply(TabularData input) {
+                return tabularDataToMap(input);
+            }};
+    }
+
+    public static Function<TabularData, Map> tabularDataToMapOfMaps() {
+        return new Function<TabularData, Map>() {
+            @Override public Map apply(TabularData input) {
+                return tabularDataToMapOfMaps(input);
+            }};
+    }
+
+    public static Function<CompositeData,Map> compositeDataToMap() {
+        return new Function<CompositeData, Map>() {
+            @Override public Map apply(CompositeData input) {
+                return compositeDataToMap(input);
+            }};
+    }
+    
+    public static Map tabularDataToMap(TabularData table) {
+        Map<String, Object> result = Maps.newLinkedHashMap();
+        for (Object entry : table.values()) {
+            CompositeData data = (CompositeData) entry; //.getValue()
+            for (String key : data.getCompositeType().keySet()) {
+                Object old = result.put(key, data.get(key));
+                if (old != null) {
+                    log.warn("tablularDataToMap has overwritten key {}", key);
+                }
+            }
+        }
+        return result;
+    }
+    
+    public static Map<List<?>, Map<String, Object>> tabularDataToMapOfMaps(TabularData table) {
+        Map<List<?>, Map<String, Object>> result = Maps.newLinkedHashMap();
+        for (Object k : table.keySet()) {
+            final Object[] kValues = ((List<?>)k).toArray();
+            CompositeData v = (CompositeData) table.get(kValues);
+            result.put((List<?>)k, compositeDataToMap(v));
+        }
+        return result;
+    }
+    
+    public static Map<String, Object> compositeDataToMap(CompositeData data) {
+        Map<String, Object> result = Maps.newLinkedHashMap();
+        for (String key : data.getCompositeType().keySet()) {
+            Object old = result.put(key, data.get(key));
+            if (old != null) {
+                log.warn("compositeDataToMap has overwritten key {}", key);
+            }
+        }
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxAttributePollConfig.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxAttributePollConfig.java b/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxAttributePollConfig.java
deleted file mode 100644
index 02bbbeb..0000000
--- a/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxAttributePollConfig.java
+++ /dev/null
@@ -1,74 +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.feed.jmx;
-
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
-
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.sensor.feed.PollConfig;
-
-import com.google.common.base.Function;
-import com.google.common.base.Functions;
-
-public class JmxAttributePollConfig<T> extends PollConfig<Object, T, JmxAttributePollConfig<T>>{
-
-    private ObjectName objectName;
-    private String attributeName;
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    public JmxAttributePollConfig(AttributeSensor<T> sensor) {
-        super(sensor);
-        onSuccess((Function)Functions.identity());
-    }
-
-    public JmxAttributePollConfig(JmxAttributePollConfig<T> other) {
-        super(other);
-        this.objectName = other.objectName;
-        this.attributeName = other.attributeName;
-    }
-
-    public ObjectName getObjectName() {
-        return objectName;
-    }
-    
-    public String getAttributeName() {
-        return attributeName;
-    }
-    
-    public JmxAttributePollConfig<T> objectName(ObjectName val) {
-        this.objectName = val; return this;
-    }
-    
-    public JmxAttributePollConfig<T> objectName(String val) {
-        try {
-            return objectName(new ObjectName(val));
-        } catch (MalformedObjectNameException e) {
-            throw new IllegalArgumentException("Invalid object name ("+val+")", e);
-        }
-    }
-    
-    public JmxAttributePollConfig<T> attributeName(String val) {
-        this.attributeName = val; return this;
-    }
-    
-    @Override protected String toStringBaseName() { return "jmx"; }
-    @Override protected String toStringPollSource() { return objectName+":"+attributeName; }
-
-}


[07/36] incubator-brooklyn git commit: Rename o.a.b.effector.core to o.a.b.core.effector

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/effector/core/Effectors.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/effector/core/Effectors.java b/core/src/main/java/org/apache/brooklyn/effector/core/Effectors.java
deleted file mode 100644
index 7f7bed4..0000000
--- a/core/src/main/java/org/apache/brooklyn/effector/core/Effectors.java
+++ /dev/null
@@ -1,202 +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.effector.core;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.api.effector.ParameterType;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.mgmt.TaskAdaptable;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.effector.core.EffectorTasks.EffectorBodyTaskFactory;
-import org.apache.brooklyn.effector.core.EffectorTasks.EffectorMarkingTaskFactory;
-import org.apache.brooklyn.effector.core.EffectorTasks.EffectorTaskFactory;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.text.Strings;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Objects;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-public class Effectors {
-
-    private static final Logger log = LoggerFactory.getLogger(Effectors.class);
-    
-    public static class EffectorBuilder<T> {
-        private Class<T> returnType;
-        private String effectorName;
-        private String description;
-        private Map<String,ParameterType<?>> parameters = new LinkedHashMap<String,ParameterType<?>>();
-        private EffectorTaskFactory<T> impl;
-        
-        private EffectorBuilder(Class<T> returnType, String effectorName) {
-            this.returnType = returnType;
-            this.effectorName = effectorName;
-        }
-        public EffectorBuilder<T> description(String description) {
-            this.description = description;
-            return this;                
-        }
-        public EffectorBuilder<T> parameter(Class<?> paramType, String paramName) {
-            return parameter(paramType, paramName, null, null);
-        }
-        public EffectorBuilder<T> parameter(Class<?> paramType, String paramName, String paramDescription) {
-            return parameter(paramType, paramName, paramDescription, null);                
-        }
-        public <V> EffectorBuilder<T> parameter(Class<V> paramType, String paramName, String paramDescription, V defaultValue) {
-            return parameter(new BasicParameterType<V>(paramName, paramType, paramDescription, defaultValue));
-        }
-        public <V> EffectorBuilder<T> parameter(ConfigKey<V> key) {
-            return parameter(asParameterType(key));
-        }
-        public EffectorBuilder<T> parameter(ParameterType<?> p) {
-            // allow redeclaring, e.g. for the case where we are overriding an existing effector
-            parameters.put(p.getName(), p);
-            return this;
-        }
-        public EffectorBuilder<T> impl(EffectorTaskFactory<T> taskFactory) {
-            this.impl = new EffectorMarkingTaskFactory<T>(taskFactory);
-            return this;
-        }
-        public EffectorBuilder<T> impl(EffectorBody<T> effectorBody) {
-            this.impl = new EffectorBodyTaskFactory<T>(effectorBody);
-            return this;
-        }
-        /** returns the effector, with an implementation (required); @see {@link #buildAbstract()} */
-        public Effector<T> build() {
-             Preconditions.checkNotNull(impl, "Cannot create effector %s with no impl (did you forget impl? or did you mean to buildAbstract?)", effectorName);
-             return new EffectorAndBody<T>(effectorName, returnType, ImmutableList.copyOf(parameters.values()), description, impl);
-        }
-        
-        /** returns an abstract effector, where the body will be defined later/elsewhere 
-         * (impl must not be set) */
-        public Effector<T> buildAbstract() {
-            Preconditions.checkArgument(impl==null, "Cannot create abstract effector {} as an impl is defined", effectorName);
-            return new EffectorBase<T>(effectorName, returnType, ImmutableList.copyOf(parameters.values()), description);
-        }
-    }
-
-    /** creates a new effector builder with the given name and return type */
-    public static <T> EffectorBuilder<T> effector(Class<T> returnType, String effectorName) {
-        return new EffectorBuilder<T>(returnType, effectorName);
-    }
-
-    /** creates a new effector builder to _override_ the given effector */
-    public static <T> EffectorBuilder<T> effector(Effector<T> base) {
-        EffectorBuilder<T> builder = new EffectorBuilder<T>(base.getReturnType(), base.getName());
-        for (ParameterType<?> p: base.getParameters())
-            builder.parameter(p);
-        builder.description(base.getDescription());
-        if (base instanceof EffectorWithBody)
-            builder.impl(((EffectorWithBody<T>) base).getBody());
-        return builder;
-    }
-
-    /** as {@link #invocation(Entity, Effector, Map)} but convenience for passing a {@link ConfigBag} */
-    public static <T> TaskAdaptable<T> invocation(Entity entity, Effector<T> eff, ConfigBag parameters) {
-        return invocation(entity, eff, parameters==null ? ImmutableMap.of() : parameters.getAllConfig());
-    }
-    
-    /** returns an unsubmitted task which invokes the given effector; use {@link Entities#invokeEffector(EntityLocal, Entity, Effector, Map)} for a submitted variant */
-    public static <T> TaskAdaptable<T> invocation(Entity entity, Effector<T> eff, @Nullable Map<?,?> parameters) {
-        @SuppressWarnings("unchecked")
-        Effector<T> eff2 = (Effector<T>) ((EntityInternal)entity).getEffector(eff.getName());
-        if (log.isTraceEnabled()) {
-            Object eff1Body = (eff instanceof EffectorWithBody<?> ? ((EffectorWithBody<?>) eff).getBody() : "bodyless");
-            String message = String.format("Invoking %s/%s on entity %s", eff, eff1Body, entity);
-            if (eff != eff2) {
-                Object eff2Body = (eff2 instanceof EffectorWithBody<?> ? ((EffectorWithBody<?>) eff2).getBody() : "bodyless");
-                message += String.format(" (actually %s/%s)", eff2, eff2Body);
-            }
-            log.trace(message);
-        }
-        if (eff2 != null) {
-            if (eff2 != eff) {
-                if (eff2 instanceof EffectorWithBody) {
-                    log.debug("Replacing invocation of {} on {} with {} which is the impl defined at that entity", new Object[] { eff, entity, eff2 });
-                    return ((EffectorWithBody<T>)eff2).getBody().newTask(entity, eff2, ConfigBag.newInstance().putAll(parameters));
-                } else {
-                    log.warn("Effector {} defined on {} has no body; invoking caller-supplied {} instead", new Object[] { eff2, entity, eff });
-                }
-            }
-        } else {
-            log.debug("Effector {} does not exist on {}; attempting to invoke anyway", new Object[] { eff, entity });
-        }
-        
-        if (eff instanceof EffectorWithBody) {
-            return ((EffectorWithBody<T>)eff).getBody().newTask(entity, eff, ConfigBag.newInstance().putAll(parameters));
-        }
-        
-        throw new UnsupportedOperationException("No implementation registered for effector "+eff+" on "+entity);
-    }    
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    public static <V> ParameterType<V> asParameterType(ConfigKey<V> key) {
-        return key.hasDefaultValue()
-            ? new BasicParameterType<V>(key.getName(), (Class)key.getType(), key.getDescription(), key.getDefaultValue())
-            : new BasicParameterType<V>(key.getName(), (Class)key.getType(), key.getDescription());
-    }
-    
-    public static <V> ConfigKey<V> asConfigKey(ParameterType<V> paramType) {
-        return ConfigKeys.newConfigKey(paramType.getParameterClass(), paramType.getName(), paramType.getDescription(), paramType.getDefaultValue());
-    }
-
-    /** returns an unsubmitted task which will invoke the given effector on the given entities;
-     * return type is Task<List<T>> (but haven't put in the blood sweat toil and tears to make the generics work) */
-    public static TaskAdaptable<List<?>> invocation(Effector<?> eff, Map<?,?> params, Iterable<? extends Entity> entities) {
-        List<TaskAdaptable<?>> tasks = new ArrayList<TaskAdaptable<?>>();
-        for (Entity e: entities) tasks.add(invocation(e, eff, params));
-        return Tasks.parallel("invoking "+eff+" on "+tasks.size()+" node"+(Strings.s(tasks.size())), tasks.toArray(new TaskAdaptable[tasks.size()]));
-    }
-
-    /** returns an unsubmitted task which will invoke the given effector on the given entities
-     * (this form of method is a convenience for {@link #invocation(Effector, Map, Iterable)}) */
-    public static TaskAdaptable<List<?>> invocation(Effector<?> eff, MutableMap<?, ?> params, Entity ...entities) {
-        return invocation(eff, params, Arrays.asList(entities));
-    }
-    
-    public static boolean sameSignature(Effector<?> e1, Effector<?> e2) {
-        return Objects.equal(e1.getName(), e2.getName()) &&
-                Objects.equal(e1.getParameters(), e2.getParameters()) &&
-                Objects.equal(e1.getReturnType(), e2.getReturnType());
-    }
-    
-    // TODO sameSignatureAndBody
-    
-    public static boolean sameInstance(Effector<?> e1, Effector<?> e2) {
-        return e1 == e2;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/effector/core/ExplicitEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/effector/core/ExplicitEffector.java b/core/src/main/java/org/apache/brooklyn/effector/core/ExplicitEffector.java
deleted file mode 100644
index 46b19ea..0000000
--- a/core/src/main/java/org/apache/brooklyn/effector/core/ExplicitEffector.java
+++ /dev/null
@@ -1,74 +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.effector.core;
-
-import groovy.lang.Closure;
-
-import java.util.List;
-import java.util.Map;
-
-import org.apache.brooklyn.api.effector.ParameterType;
-import org.apache.brooklyn.api.entity.Entity;
-
-import com.google.common.base.Objects;
-import com.google.common.collect.ImmutableList;
-
-public abstract class ExplicitEffector<I,T> extends AbstractEffector<T> {
-    public ExplicitEffector(String name, Class<T> type, String description) {
-        this(name, type, ImmutableList.<ParameterType<?>>of(), description);
-    }
-    public ExplicitEffector(String name, Class<T> type, List<ParameterType<?>> parameters, String description) {
-        super(name, type, parameters, description);
-    }
-
-    public T call(Entity entity, Map parameters) {
-        return invokeEffector((I) entity, (Map<String,?>)parameters );
-    }
-
-    public abstract T invokeEffector(I trait, Map<String,?> parameters);
-    
-    /** convenience to create an effector supplying a closure; annotations are preferred,
-     * and subclass here would be failback, but this is offered as 
-     * workaround for bug GROOVY-5122, as discussed in test class CanSayHi 
-     */
-    public static <I,T> ExplicitEffector<I,T> create(String name, Class<T> type, List<ParameterType<?>> parameters, String description, Closure body) {
-        return new ExplicitEffectorFromClosure<I,T>(name, type, parameters, description, body);
-    }
-    
-    private static class ExplicitEffectorFromClosure<I,T> extends ExplicitEffector<I,T> {
-        private static final long serialVersionUID = -5771188171702382236L;
-        final Closure<T> body;
-        public ExplicitEffectorFromClosure(String name, Class<T> type, List<ParameterType<?>> parameters, String description, Closure<T> body) {
-            super(name, type, parameters, description);
-            this.body = body;
-        }
-        public T invokeEffector(I trait, Map<String,?> parameters) { return body.call(trait, parameters); }
-        
-        @Override
-        public int hashCode() {
-            return Objects.hashCode(super.hashCode(), body);
-        }
-        
-        @Override
-        public boolean equals(Object other) {
-            return super.equals(other) && Objects.equal(body, ((ExplicitEffectorFromClosure<?,?>)other).body);
-        }
-        
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/effector/core/MethodEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/effector/core/MethodEffector.java b/core/src/main/java/org/apache/brooklyn/effector/core/MethodEffector.java
deleted file mode 100644
index 7dd0828..0000000
--- a/core/src/main/java/org/apache/brooklyn/effector/core/MethodEffector.java
+++ /dev/null
@@ -1,180 +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.effector.core;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.api.effector.ParameterType;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.core.annotation.EffectorParam;
-import org.apache.brooklyn.core.entity.AbstractEntity;
-import org.apache.brooklyn.core.mgmt.internal.EffectorUtils;
-import org.apache.brooklyn.util.core.flags.TypeCoercions;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.groovy.GroovyJavaMethods;
-import org.codehaus.groovy.runtime.MethodClosure;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.Lists;
-
-/** concrete class for providing an Effector implementation that gets its information from annotations on a method;
- * see Effector*Test for usage example.
- * <p>
- * note that the method must be on an interface in order for it to be remoted, with the current implementation.
- * see comments in {@link #call(Entity, Map)} for more details.
- */
-public class MethodEffector<T> extends AbstractEffector<T> {
-
-    private static final long serialVersionUID = 6989688364011965968L;
-    private static final Logger log = LoggerFactory.getLogger(MethodEffector.class);
-    
-    @SuppressWarnings("rawtypes")
-    public static Effector<?> create(Method m) {
-        return new MethodEffector(m);
-    }
-    
-    protected static class AnnotationsOnMethod {
-        final Class<?> clazz;
-        final String name;
-        final String description;
-        final Class<?> returnType;
-        final List<ParameterType<?>> parameters;
-
-        public AnnotationsOnMethod(Class<?> clazz, String methodName) {
-            this(clazz, inferBestMethod(clazz, methodName));
-        }
-
-        public AnnotationsOnMethod(Class<?> clazz, Method method) {
-            this.clazz = clazz;
-            this.name = method.getName();
-            this.returnType = method.getReturnType();
-
-            // Get the description
-            org.apache.brooklyn.core.annotation.Effector effectorAnnotation = method.getAnnotation(org.apache.brooklyn.core.annotation.Effector.class);
-            description = (effectorAnnotation != null) ? effectorAnnotation.description() : null;
-
-            // Get the parameters
-            parameters = Lists.newArrayList();
-            int numParameters = method.getParameterTypes().length;
-            for (int i = 0; i < numParameters; i++) {
-                parameters.add(toParameterType(method, i));
-            }
-        }
-
-        @SuppressWarnings({ "rawtypes", "unchecked" })
-        protected static ParameterType<?> toParameterType(Method method, int paramIndex) {
-            Annotation[] anns = method.getParameterAnnotations()[paramIndex];
-            Class<?> type = method.getParameterTypes()[paramIndex];
-            EffectorParam paramAnnotation = findAnnotation(anns, EffectorParam.class);
-
-            // TODO if blank, could do "param"+(i+1); would that be better?
-            // TODO this will now give "" if name is blank, rather than previously null. Is that ok?!
-            String name = (paramAnnotation != null) ? paramAnnotation.name() : null;
-
-            String paramDescription = (paramAnnotation == null || EffectorParam.MAGIC_STRING_MEANING_NULL.equals(paramAnnotation.description())) ? null : paramAnnotation.description();
-            String description = (paramDescription != null) ? paramDescription : null;
-
-            String paramDefaultValue = (paramAnnotation == null || EffectorParam.MAGIC_STRING_MEANING_NULL.equals(paramAnnotation.defaultValue())) ? null : paramAnnotation.defaultValue();
-            Object defaultValue = (paramDefaultValue != null) ? TypeCoercions.coerce(paramDefaultValue, type) : null;
-
-            return new BasicParameterType(name, type, description, defaultValue);
-        }
-        
-        @SuppressWarnings("unchecked")
-        protected static <T extends Annotation> T findAnnotation(Annotation[] anns, Class<T> type) {
-            for (Annotation ann : anns) {
-                if (type.isInstance(ann)) return (T) ann;
-            }
-            return null;
-        }
-        
-        protected static Method inferBestMethod(Class<?> clazz, String methodName) {
-            Method best = null;
-            for (Method it : clazz.getMethods()) { 
-                if (it.getName().equals(methodName)) {
-                    if (best==null || best.getParameterTypes().length < it.getParameterTypes().length) best=it;
-                }
-            }
-            if (best==null) {
-                throw new IllegalStateException("Cannot find method "+methodName+" on "+clazz.getCanonicalName());
-            }
-            return best;
-        }
-    }
-
-    /** Defines a new effector whose details are supplied as annotations on the given type and method name */
-    public MethodEffector(Class<?> whereEffectorDefined, String methodName) {
-        this(new AnnotationsOnMethod(whereEffectorDefined, methodName), null);
-    }
-
-    public MethodEffector(Method method) {
-        this(new AnnotationsOnMethod(method.getDeclaringClass(), method), null);
-    }
-
-    public MethodEffector(MethodClosure mc) {
-        this(new AnnotationsOnMethod((Class<?>)mc.getDelegate(), mc.getMethod()), null);
-    }
-
-    @SuppressWarnings("unchecked")
-    protected MethodEffector(AnnotationsOnMethod anns, String description) {
-        super(anns.name, (Class<T>)anns.returnType, anns.parameters, GroovyJavaMethods.<String>elvis(description, anns.description));
-    }
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    public T call(Entity entity, Map parameters) {
-        Object[] parametersArray = EffectorUtils.prepareArgsForEffector(this, parameters);
-        if (entity instanceof AbstractEntity) {
-            return EffectorUtils.invokeMethodEffector(entity, this, parametersArray);
-        } else {
-            // we are dealing with a proxy here
-            // this implementation invokes the method on the proxy
-            // (requiring it to be on the interface)
-            // and letting the proxy deal with the remoting / runAtEntity;
-            // alternatively we could create the task here and pass it to runAtEntity;
-            // the latter may allow us to simplify/remove a lot of the stuff from 
-            // EffectorUtils and possibly Effectors and Entities
-            
-            // TODO Should really find method with right signature, rather than just the right args.
-            // TODO prepareArgs can miss things out that have "default values"! Code below will probably fail if that happens.
-            Method[] methods = entity.getClass().getMethods();
-            for (Method method : methods) {
-                if (method.getName().equals(getName())) {
-                    if (parametersArray.length == method.getParameterTypes().length) {
-                        try {
-                            return (T) method.invoke(entity, parametersArray);
-                        } catch (Exception e) {
-                            // exception handled by the proxy invocation (which leads to EffectorUtils.invokeEffectorMethod...)
-                            throw Exceptions.propagate(e);
-                        }
-                    }
-                }
-            }
-            String msg = "Could not find method for effector "+getName()+" with "+parametersArray.length+" parameters on "+entity;
-            log.warn(msg+" (throwing); available methods are: "+Arrays.toString(methods));
-            throw new IllegalStateException(msg);
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/effector/core/ssh/SshEffectorTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/effector/core/ssh/SshEffectorTasks.java b/core/src/main/java/org/apache/brooklyn/effector/core/ssh/SshEffectorTasks.java
deleted file mode 100644
index b904ba7..0000000
--- a/core/src/main/java/org/apache/brooklyn/effector/core/ssh/SshEffectorTasks.java
+++ /dev/null
@@ -1,334 +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.effector.core.ssh;
-
-import java.util.List;
-import java.util.Map;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.mgmt.Task;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.config.StringConfigMap;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.config.ConfigUtils;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.core.location.internal.LocationInternal;
-import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.effector.core.EffectorBody;
-import org.apache.brooklyn.effector.core.EffectorTasks;
-import org.apache.brooklyn.effector.core.EffectorTasks.EffectorTaskFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.core.internal.ssh.SshTool;
-import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.core.task.ssh.SshFetchTaskFactory;
-import org.apache.brooklyn.util.core.task.ssh.SshFetchTaskWrapper;
-import org.apache.brooklyn.util.core.task.ssh.SshPutTaskFactory;
-import org.apache.brooklyn.util.core.task.ssh.SshPutTaskWrapper;
-import org.apache.brooklyn.util.core.task.ssh.SshTasks;
-import org.apache.brooklyn.util.core.task.ssh.internal.AbstractSshExecTaskFactory;
-import org.apache.brooklyn.util.core.task.ssh.internal.PlainSshExecTaskFactory;
-import org.apache.brooklyn.util.core.task.system.ProcessTaskFactory;
-import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
-import org.apache.brooklyn.util.ssh.BashCommands;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Function;
-import com.google.common.collect.Maps;
-
-/**
- * Conveniences for generating {@link Task} instances to perform SSH activities.
- * <p>
- * If the {@link SshMachineLocation machine} is not specified directly it
- * will be inferred from the {@link Entity} context of either the {@link Effector}
- * or the current {@link Task}.
- * 
- * @see SshTasks
- * @since 0.6.0
- */
-@Beta
-public class SshEffectorTasks {
-
-    private static final Logger log = LoggerFactory.getLogger(SshEffectorTasks.class);
-    
-    public static final ConfigKey<Boolean> IGNORE_ENTITY_SSH_FLAGS = ConfigKeys.newBooleanConfigKey("ignoreEntitySshFlags",
-        "Whether to ignore any ssh flags (behaviour constraints) set on the entity or location " +
-        "where this is running, using only flags explicitly specified", false);
-    
-    /**
-     * Like {@link EffectorBody} but providing conveniences when in an entity with a single machine location.
-     */
-    public abstract static class SshEffectorBody<T> extends EffectorBody<T> {
-        
-        /** convenience for accessing the machine */
-        public SshMachineLocation machine() {
-            return EffectorTasks.getSshMachine(entity());
-        }
-
-        /** convenience for generating an {@link PlainSshExecTaskFactory} which can be further customised if desired, and then (it must be explicitly) queued */
-        public ProcessTaskFactory<Integer> ssh(String ...commands) {
-            return new SshEffectorTaskFactory<Integer>(commands).machine(machine());
-        }
-    }
-
-    /** variant of {@link PlainSshExecTaskFactory} which fulfills the {@link EffectorTaskFactory} signature so can be used directly as an impl for an effector,
-     * also injects the machine automatically; can also be used outwith effector contexts, and machine is still injected if it is
-     * run from inside a task at an entity with a single SshMachineLocation */
-    public static class SshEffectorTaskFactory<RET> extends AbstractSshExecTaskFactory<SshEffectorTaskFactory<RET>,RET> implements EffectorTaskFactory<RET> {
-
-        public SshEffectorTaskFactory(String ...commands) {
-            super(commands);
-        }
-        public SshEffectorTaskFactory(SshMachineLocation machine, String ...commands) {
-            super(machine, commands);
-        }
-        @Override
-        public ProcessTaskWrapper<RET> newTask(Entity entity, Effector<RET> effector, ConfigBag parameters) {
-            markDirty();
-            if (summary==null) summary(effector.getName()+" (ssh)");
-            machine(EffectorTasks.getSshMachine(entity));
-            return newTask();
-        }
-        @Override
-        public synchronized ProcessTaskWrapper<RET> newTask() {
-            Entity entity = BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
-            if (machine==null) {
-                if (log.isDebugEnabled())
-                    log.debug("Using an ssh task not in an effector without any machine; will attempt to infer the machine: "+this);
-                if (entity!=null)
-                    machine(EffectorTasks.getSshMachine(entity));
-            }
-            applySshFlags(getConfig(), entity, getMachine());
-            return super.newTask();
-        }
-        
-        @Override
-        public <T2> SshEffectorTaskFactory<T2> returning(ScriptReturnType type) {
-            return (SshEffectorTaskFactory<T2>) super.<T2>returning(type);
-        }
-
-        @Override
-        public SshEffectorTaskFactory<Boolean> returningIsExitCodeZero() {
-            return (SshEffectorTaskFactory<Boolean>) super.returningIsExitCodeZero();
-        }
-
-        public SshEffectorTaskFactory<String> requiringZeroAndReturningStdout() {
-            return (SshEffectorTaskFactory<String>) super.requiringZeroAndReturningStdout();
-        }
-        
-        public <RET2> SshEffectorTaskFactory<RET2> returning(Function<ProcessTaskWrapper<?>, RET2> resultTransformation) {
-            return (SshEffectorTaskFactory<RET2>) super.returning(resultTransformation);
-        }
-    }
-    
-    public static class SshPutEffectorTaskFactory extends SshPutTaskFactory implements EffectorTaskFactory<Void> {
-        public SshPutEffectorTaskFactory(String remoteFile) {
-            super(remoteFile);
-        }
-        public SshPutEffectorTaskFactory(SshMachineLocation machine, String remoteFile) {
-            super(machine, remoteFile);
-        }
-        @Override
-        public SshPutTaskWrapper newTask(Entity entity, Effector<Void> effector, ConfigBag parameters) {
-            machine(EffectorTasks.getSshMachine(entity));
-            applySshFlags(getConfig(), entity, getMachine());
-            return super.newTask();
-        }
-        @Override
-        public SshPutTaskWrapper newTask() {
-            Entity entity = BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
-            if (machine==null) {
-                if (log.isDebugEnabled())
-                    log.debug("Using an ssh put task not in an effector without any machine; will attempt to infer the machine: "+this);
-                if (entity!=null) {
-                    machine(EffectorTasks.getSshMachine(entity));
-                }
-
-            }
-            applySshFlags(getConfig(), entity, getMachine());
-            return super.newTask();
-        }
-    }
-
-    public static class SshFetchEffectorTaskFactory extends SshFetchTaskFactory implements EffectorTaskFactory<String> {
-        public SshFetchEffectorTaskFactory(String remoteFile) {
-            super(remoteFile);
-        }
-        public SshFetchEffectorTaskFactory(SshMachineLocation machine, String remoteFile) {
-            super(machine, remoteFile);
-        }
-        @Override
-        public SshFetchTaskWrapper newTask(Entity entity, Effector<String> effector, ConfigBag parameters) {
-            machine(EffectorTasks.getSshMachine(entity));
-            applySshFlags(getConfig(), entity, getMachine());
-            return super.newTask();
-        }
-        @Override
-        public SshFetchTaskWrapper newTask() {
-            Entity entity = BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
-            if (machine==null) {
-                if (log.isDebugEnabled())
-                    log.debug("Using an ssh fetch task not in an effector without any machine; will attempt to infer the machine: "+this);
-                if (entity!=null)
-                    machine(EffectorTasks.getSshMachine(entity));
-            }
-            applySshFlags(getConfig(), entity, getMachine());
-            return super.newTask();
-        }
-    }
-
-    public static SshEffectorTaskFactory<Integer> ssh(String ...commands) {
-        return new SshEffectorTaskFactory<Integer>(commands);
-    }
-
-    public static SshEffectorTaskFactory<Integer> ssh(List<String> commands) {
-        return ssh(commands.toArray(new String[commands.size()]));
-    }
-
-    public static SshPutTaskFactory put(String remoteFile) {
-        return new SshPutEffectorTaskFactory(remoteFile);
-    }
-
-    public static SshFetchEffectorTaskFactory fetch(String remoteFile) {
-        return new SshFetchEffectorTaskFactory(remoteFile);
-    }
-
-    /** task which returns 0 if pid is running */
-    public static SshEffectorTaskFactory<Integer> codePidRunning(Integer pid) {
-        return ssh("ps -p "+pid).summary("PID "+pid+" is-running check (exit code)").allowingNonZeroExitCode();
-    }
-    
-    /** task which fails if the given PID is not running */
-    public static SshEffectorTaskFactory<?> requirePidRunning(Integer pid) {
-        return codePidRunning(pid).summary("PID "+pid+" is-running check (required)").requiringExitCodeZero("Process with PID "+pid+" is required to be running");
-    }
-
-    /** as {@link #codePidRunning(Integer)} but returning boolean */
-    public static SshEffectorTaskFactory<Boolean> isPidRunning(Integer pid) {
-        return codePidRunning(pid).summary("PID "+pid+" is-running check (boolean)").returning(new Function<ProcessTaskWrapper<?>, Boolean>() {
-            public Boolean apply(@Nullable ProcessTaskWrapper<?> input) { return Integer.valueOf(0).equals(input.getExitCode()); }
-        });
-    }
-
-
-    /** task which returns 0 if pid in the given file is running;
-     * method accepts wildcards so long as they match a single file on the remote end
-     * <p>
-     * returns 1 if no matching file, 
-     * 1 if matching file but no matching process,
-     * and 2 if 2+ matching files */
-    public static SshEffectorTaskFactory<Integer> codePidFromFileRunning(final String pidFile) {
-        return ssh(BashCommands.chain(
-                // this fails, but isn't an error
-                BashCommands.requireTest("-f "+pidFile, "The PID file "+pidFile+" does not exist."),
-                // this fails and logs an error picked up later
-                BashCommands.requireTest("`ls "+pidFile+" | wc -w` -eq 1", "ERROR: there are multiple matching PID files"),
-                // this fails and logs an error picked up later
-                BashCommands.require("cat "+pidFile, "ERROR: the PID file "+pidFile+" cannot be read (permissions?)."),
-                // finally check the process
-                "ps -p `cat "+pidFile+"`")).summary("PID file "+pidFile+" is-running check (exit code)")
-                .allowingNonZeroExitCode()
-                .addCompletionListener(new Function<ProcessTaskWrapper<?>,Void>() {
-                    public Void apply(ProcessTaskWrapper<?> input) {
-                        if (input.getStderr().contains("ERROR:"))
-                            throw new IllegalStateException("Invalid or inaccessible PID filespec: "+pidFile);
-                        return null;
-                    }
-                });
-    }
-    
-    /** task which fails if the pid in the given file is not running (or if there is no such PID file);
-     * method accepts wildcards so long as they match a single file on the remote end (fails if 0 or 2+ matching files) */
-    public static SshEffectorTaskFactory<?> requirePidFromFileRunning(String pidFile) {
-        return codePidFromFileRunning(pidFile)
-                .summary("PID file "+pidFile+" is-running check (required)")
-                .requiringExitCodeZero("Process with PID from file "+pidFile+" is required to be running");
-    }
-
-    /** as {@link #codePidFromFileRunning(String)} but returning boolean */
-    public static SshEffectorTaskFactory<Boolean> isPidFromFileRunning(String pidFile) {
-        return codePidFromFileRunning(pidFile).summary("PID file "+pidFile+" is-running check (boolean)").
-                returning(new Function<ProcessTaskWrapper<?>, Boolean>() {
-                    public Boolean apply(@Nullable ProcessTaskWrapper<?> input) { return ((Integer)0).equals(input.getExitCode()); }
-                });
-    }
-
-    /** extracts the values for the main brooklyn.ssh.config.* config keys (i.e. those declared in ConfigKeys) 
-     * as declared on the entity, and inserts them in a map using the unprefixed state, for ssh.
-     * <p>
-     * currently this is computed for each call, which may be wasteful, but it is reliable in the face of config changes.
-     * we could cache the Map.  note that we do _not_ cache (or even own) the SshTool; 
-     * the SshTool is created or re-used by the SshMachineLocation making use of these properties */
-    @Beta
-    public static Map<String, Object> getSshFlags(Entity entity, Location optionalLocation) {
-        ConfigBag allConfig = ConfigBag.newInstance();
-        
-        StringConfigMap globalConfig = ((EntityInternal)entity).getManagementContext().getConfig();
-        allConfig.putAll(globalConfig.getAllConfig());
-        
-        if (optionalLocation!=null)
-            allConfig.putAll(((LocationInternal)optionalLocation).config().getBag());
-        
-        allConfig.putAll(((EntityInternal)entity).getAllConfig());
-        
-        Map<String, Object> result = Maps.newLinkedHashMap();
-        for (String keyS : allConfig.getAllConfig().keySet()) {
-            if (keyS.startsWith(SshTool.BROOKLYN_CONFIG_KEY_PREFIX)) {
-                ConfigKey<?> key = ConfigKeys.newConfigKey(Object.class, keyS);
-                
-                Object val = allConfig.getStringKey(keyS);
-                
-                /*
-                 * NOV 2013 changing this to rely on config above being inserted in the right order,
-                 * so entity config will be preferred over location, and location over global.
-                 * If that is consistent then remove the lines below.
-                 * (We can also accept null entity and so combine with SshTasks.getSshFlags.)
-                 */
-                
-//                // have to use raw config to test whether the config is set
-//                Object val = ((EntityInternal)entity).getConfigMap().getRawConfig(key);
-//                if (val!=null) {
-//                    val = entity.getConfig(key);
-//                } else {
-//                    val = globalConfig.getRawConfig(key);
-//                    if (val!=null) val = globalConfig.getConfig(key);
-//                }
-//                if (val!=null) {
-                    result.put(ConfigUtils.unprefixedKey(SshTool.BROOKLYN_CONFIG_KEY_PREFIX, key).getName(), val);
-//                }
-            }
-        }
-        return result;
-    }
-
-    private static void applySshFlags(ConfigBag config, Entity entity, Location machine) {
-        if (entity!=null) {
-            if (!config.get(IGNORE_ENTITY_SSH_FLAGS)) {
-                config.putIfAbsent(getSshFlags(entity, machine));
-            }
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicCluster.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicCluster.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicCluster.java
index 1b16369..bf39663 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicCluster.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicCluster.java
@@ -33,11 +33,11 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.annotation.EffectorParam;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.factory.EntityFactory;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.trait.MemberReplaceable;
-import org.apache.brooklyn.effector.core.MethodEffector;
 import org.apache.brooklyn.entity.group.zoneaware.BalancingNodePlacementStrategy;
 import org.apache.brooklyn.entity.group.zoneaware.ProportionalZoneFailureDetector;
 import org.apache.brooklyn.sensor.core.BasicAttributeSensor;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java
index 7a0c31b..a8c63ef 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java
@@ -39,6 +39,7 @@ import org.apache.brooklyn.api.location.MachineProvisioningLocation;
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.core.config.render.RendererHints;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.factory.EntityFactory;
 import org.apache.brooklyn.core.entity.factory.EntityFactoryForLocation;
@@ -50,7 +51,6 @@ import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.entity.trait.StartableMethods;
 import org.apache.brooklyn.core.location.Locations;
 import org.apache.brooklyn.core.location.cloud.AvailabilityZoneExtension;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.entity.stock.DelegateEntity;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java
index 7611ba8..daedc39 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java
@@ -32,6 +32,7 @@ import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.factory.EntityFactory;
@@ -40,7 +41,6 @@ import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.trait.Changeable;
 import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.exceptions.Exceptions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicGroup.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicGroup.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicGroup.java
index 36ac0f9..bb43d3b 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicGroup.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicGroup.java
@@ -28,8 +28,8 @@ import org.apache.brooklyn.api.sensor.SensorEvent;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.effector.core.MethodEffector;
 import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicRegionsFabric.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicRegionsFabric.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicRegionsFabric.java
index fc11e9b..7c46d14 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicRegionsFabric.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicRegionsFabric.java
@@ -21,7 +21,7 @@ package org.apache.brooklyn.entity.group;
 import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.annotation.EffectorParam;
-import org.apache.brooklyn.effector.core.MethodEffector;
+import org.apache.brooklyn.core.effector.MethodEffector;
 
 @ImplementedBy(DynamicRegionsFabricImpl.class)
 public interface DynamicRegionsFabric extends DynamicFabric {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/entity/group/QuarantineGroupImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/QuarantineGroupImpl.java b/core/src/main/java/org/apache/brooklyn/entity/group/QuarantineGroupImpl.java
index dfddf5f..886862a 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/QuarantineGroupImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/QuarantineGroupImpl.java
@@ -23,10 +23,10 @@ import java.util.Set;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
 import org.apache.brooklyn.util.core.task.Tasks;
 import org.apache.brooklyn.util.exceptions.Exceptions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/sensor/core/HttpRequestSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/HttpRequestSensor.java b/core/src/main/java/org/apache/brooklyn/sensor/core/HttpRequestSensor.java
index 7a5fecf..6b9c780 100644
--- a/core/src/main/java/org/apache/brooklyn/sensor/core/HttpRequestSensor.java
+++ b/core/src/main/java/org/apache/brooklyn/sensor/core/HttpRequestSensor.java
@@ -25,7 +25,7 @@ import net.minidev.json.JSONObject;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.effector.core.AddSensor;
+import org.apache.brooklyn.core.effector.AddSensor;
 import org.apache.brooklyn.sensor.feed.http.HttpFeed;
 import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
 import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/sensor/core/StaticSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/StaticSensor.java b/core/src/main/java/org/apache/brooklyn/sensor/core/StaticSensor.java
index 7bc10bf..0c3a00f 100644
--- a/core/src/main/java/org/apache/brooklyn/sensor/core/StaticSensor.java
+++ b/core/src/main/java/org/apache/brooklyn/sensor/core/StaticSensor.java
@@ -22,7 +22,7 @@ import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.effector.core.AddSensor;
+import org.apache.brooklyn.core.effector.AddSensor;
 import org.apache.brooklyn.sensor.enricher.Propagator;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.task.Tasks;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeed.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeed.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeed.java
index 33b284c..95aba9f 100644
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeed.java
+++ b/core/src/main/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeed.java
@@ -40,8 +40,8 @@ import org.apache.brooklyn.api.mgmt.ExecutionContext;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.EffectorTasks;
 import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.effector.core.EffectorTasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.location.winrm.WinRmMachineLocation;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshTasks.java b/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshTasks.java
index 10eea13..448cd61 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshTasks.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshTasks.java
@@ -32,10 +32,10 @@ import org.apache.brooklyn.api.mgmt.TaskQueueingContext;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.config.ConfigUtils;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.location.AbstractLocation;
 import org.apache.brooklyn.core.location.internal.LocationInternal;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorBasicTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorBasicTest.java b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorBasicTest.java
new file mode 100644
index 0000000..b05a397
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorBasicTest.java
@@ -0,0 +1,183 @@
+/*
+ * 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.core.effector;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.mgmt.HasTaskChildren;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.trait.FailingEntity;
+import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.location.SimulatedLocation;
+import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.test.TestUtils;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.task.Tasks;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+
+public class EffectorBasicTest extends BrooklynAppUnitTestSupport {
+
+    private static final Logger log = LoggerFactory.getLogger(EffectorBasicTest.class);
+    
+    // NB: more tests of effectors in EffectorSayHiTest and EffectorConcatenateTest
+    // as well as EntityConfigMapUsageTest and others
+
+    private List<SimulatedLocation> locs;
+    
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        locs = ImmutableList.of(new SimulatedLocation());
+    }
+    
+    @Test
+    public void testInvokeEffectorStart() {
+        app.start(locs);
+        TestUtils.assertSetsEqual(locs, app.getLocations());
+        // TODO above does not get registered as a task
+    }
+
+    @Test
+    public void testInvokeEffectorStartWithMap() {
+        app.invoke(Startable.START, MutableMap.of("locations", locs)).getUnchecked();
+        TestUtils.assertSetsEqual(locs, app.getLocations());
+    }
+
+    @Test
+    public void testInvokeEffectorStartWithArgs() {
+        Entities.invokeEffectorWithArgs((EntityLocal)app, app, Startable.START, locs).getUnchecked();
+        TestUtils.assertSetsEqual(locs, app.getLocations());
+    }
+
+    @Test
+    public void testInvokeEffectorStartWithTwoEntities() {
+        TestEntity entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        TestEntity entity2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        app.start(locs);
+        TestUtils.assertSetsEqual(locs, app.getLocations());
+        TestUtils.assertSetsEqual(locs, entity.getLocations());
+        TestUtils.assertSetsEqual(locs, entity2.getLocations());
+    }
+    
+    @Test
+    public void testInvokeEffectorTaskHasTag() {
+        Task<Void> starting = app.invoke(Startable.START, MutableMap.of("locations", locs));
+//        log.info("TAGS: "+starting.getTags());
+        Assert.assertTrue(starting.getTags().contains(ManagementContextInternal.EFFECTOR_TAG));
+    }
+
+    // check various failure situations
+    
+    private FailingEntity createFailingEntity() {
+        FailingEntity entity = app.createAndManageChild(EntitySpec.create(FailingEntity.class)
+            .configure(FailingEntity.FAIL_ON_START, true));
+        return entity;
+    }
+
+    // uncaught failures are propagates
+    
+    @Test
+    public void testInvokeEffectorStartFailing_Method() {
+        FailingEntity entity = createFailingEntity();
+        assertStartMethodFails(entity);
+    }
+
+    @Test
+    public void testInvokeEffectorStartFailing_EntityInvoke() {
+        FailingEntity entity = createFailingEntity();
+        assertTaskFails( entity.invoke(Startable.START, MutableMap.of("locations", locs)) );
+    }
+     
+    @Test
+    public void testInvokeEffectorStartFailing_EntitiesInvoke() {
+        FailingEntity entity = createFailingEntity();
+        
+        assertTaskFails( Entities.invokeEffectorWithArgs(entity, entity, Startable.START, locs) );
+    }
+
+    // caught failures are NOT propagated!
+    
+    @Test
+    public void testInvokeEffectorStartFailing_MethodInDynamicTask() {
+        Task<Void> task = app.getExecutionContext().submit(Tasks.<Void>builder().dynamic(true).body(new Callable<Void>() {
+            @Override public Void call() throws Exception {
+                testInvokeEffectorStartFailing_Method();
+                return null;
+            }
+        }).build());
+        
+        assertTaskSucceeds(task);
+        assertTaskHasFailedChild(task);
+    }
+
+    @Test
+    public void testInvokeEffectorStartFailing_MethodInTask() {
+        Task<Void> task = app.getExecutionContext().submit(Tasks.<Void>builder().dynamic(false).body(new Callable<Void>() {
+            @Override public Void call() throws Exception {
+                testInvokeEffectorStartFailing_Method();
+                return null;
+            }
+        }).build());
+        
+        assertTaskSucceeds(task);
+    }
+
+    private void assertTaskSucceeds(Task<Void> task) {
+        task.getUnchecked();
+        Assert.assertFalse(task.isError());
+    }
+
+    private void assertTaskHasFailedChild(Task<Void> task) {
+        Assert.assertTrue(Tasks.failed( ((HasTaskChildren)task).getChildren() ).iterator().hasNext());
+    }
+        
+    private void assertStartMethodFails(FailingEntity entity) {
+        try {
+            entity.start(locs);
+            Assert.fail("Should have failed");
+        } catch (Exception e) {
+            // expected
+        }
+    }
+     
+    protected void assertTaskFails(Task<?> t) {
+        try {
+            t.get();
+            Assert.fail("Should have failed");
+        } catch (Exception e) {
+            Exceptions.propagateIfFatal(e);
+            // expected
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorConcatenateTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorConcatenateTest.java b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorConcatenateTest.java
new file mode 100644
index 0000000..c909a9d
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorConcatenateTest.java
@@ -0,0 +1,241 @@
+/*
+ * 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.core.effector;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.fail;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.mgmt.ExecutionManager;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.annotation.Effector;
+import org.apache.brooklyn.core.annotation.EffectorParam;
+import org.apache.brooklyn.core.effector.MethodEffector;
+import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.core.test.entity.TestApplicationImpl;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.task.BasicExecutionContext;
+import org.apache.brooklyn.util.core.task.Tasks;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+
+public class EffectorConcatenateTest {
+
+    
+    private static final Logger log = LoggerFactory.getLogger(EffectorConcatenateTest.class);
+    private static final long TIMEOUT = 10*1000;
+    
+    public static class MyEntityImpl extends AbstractEntity {
+
+        public static MethodEffector<String> CONCATENATE = new MethodEffector<String>(MyEntityImpl.class, "concatenate");
+        public static MethodEffector<Void> WAIT_A_BIT = new MethodEffector<Void>(MyEntityImpl.class, "waitabit");
+        public static MethodEffector<Void> SPAWN_CHILD = new MethodEffector<Void>(MyEntityImpl.class, "spawnchild");
+
+        public MyEntityImpl() {
+            super();
+        }
+        public MyEntityImpl(Entity parent) {
+            super(parent);
+        }
+
+        /** The "current task" representing the effector currently executing */
+        AtomicReference<Task<?>> waitingTask = new AtomicReference<Task<?>>();
+        
+        /** latch is .countDown'ed by the effector at the beginning of the "waiting" point */
+        CountDownLatch nowWaitingLatch = new CountDownLatch(1);
+        
+        /** latch is await'ed on by the effector when it is in the "waiting" point */
+        CountDownLatch continueFromWaitingLatch = new CountDownLatch(1);
+        
+        @Effector(description="sample effector concatenating strings")
+        public String concatenate(@EffectorParam(name="first", description="first argument") String first,
+                @EffectorParam(name="second", description="2nd arg") String second) throws Exception {
+            return first+second;
+        }
+        
+        @Effector(description="sample effector doing some waiting")
+        public void waitabit() throws Exception {
+            waitingTask.set(Tasks.current());
+            
+            Tasks.setExtraStatusDetails("waitabit extra status details");
+            
+            Tasks.withBlockingDetails("waitabit.blocking", new Callable<Void>() {
+                    public Void call() throws Exception {
+                        nowWaitingLatch.countDown();
+                        if (!continueFromWaitingLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
+                            fail("took too long to be told to continue");
+                        }
+                        return null;
+                    }});
+        }
+        
+        @Effector(description="sample effector that spawns a child task that waits a bit")
+        public void spawnchild() throws Exception {
+            // spawn a child, then wait
+            BasicExecutionContext.getCurrentExecutionContext().submit(
+                    MutableMap.of("displayName", "SpawnedChildName"),
+                    new Callable<Void>() {
+                        public Void call() throws Exception {
+                            log.info("beginning spawned child response "+Tasks.current()+", with tags "+Tasks.current().getTags());
+                            Tasks.setBlockingDetails("spawned child blocking details");
+                            nowWaitingLatch.countDown();
+                            if (!continueFromWaitingLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
+                                fail("took too long to be told to continue");
+                            }
+                            return null;
+                        }});
+        }
+    }
+            
+    private TestApplication app;
+    private MyEntityImpl e;
+    
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() {
+        app = new TestApplicationImpl();
+        e = new MyEntityImpl(app);
+        Entities.startManagement(app);
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+    
+    @Test
+    public void testCanInvokeEffector() throws Exception {
+        // invocation map syntax
+        Task<String> task = e.invoke(MyEntityImpl.CONCATENATE, ImmutableMap.of("first", "a", "second", "b"));
+        assertEquals(task.get(TIMEOUT, TimeUnit.MILLISECONDS), "ab");
+
+        // method syntax
+        assertEquals("xy", e.concatenate("x", "y"));
+    }
+    
+    @Test
+    public void testReportsTaskDetails() throws Exception {
+        final AtomicReference<String> result = new AtomicReference<String>();
+
+        Thread bg = new Thread(new Runnable() {
+            public void run() {
+                try {
+                    // Expect "wait a bit" to tell us it's blocking 
+                    if (!e.nowWaitingLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
+                        result.set("took too long for waitabit to be waiting");
+                        return;
+                    }
+
+                    // Expect "wait a bit" to have retrieved and set its task
+                    try {
+                        Task<?> t = e.waitingTask.get();
+                        String status = t.getStatusDetail(true);
+                        log.info("waitabit task says:\n"+status);
+                        if (!status.contains("waitabit extra status details")) {
+                            result.set("Status not in expected format: doesn't contain extra status details phrase 'My extra status details'\n"+status);
+                            return;
+                        }
+                        if (!status.startsWith("waitabit.blocking")) {
+                            result.set("Status not in expected format: doesn't start with blocking details 'waitabit.blocking'\n"+status);
+                            return;
+                        }
+                    } finally {
+                        e.continueFromWaitingLatch.countDown();
+                    }
+                } catch (Throwable t) {
+                    log.warn("Failure: "+t, t);
+                    result.set("Failure: "+t);
+                }
+            }});
+        bg.start();
+    
+        e.invoke(MyEntityImpl.WAIT_A_BIT, ImmutableMap.<String,Object>of())
+                .get(TIMEOUT, TimeUnit.MILLISECONDS);
+        
+        bg.join(TIMEOUT*2);
+        assertFalse(bg.isAlive());
+        
+        String problem = result.get();
+        if (problem!=null) fail(problem);
+    }
+    
+    @Test
+    public void testReportsSpawnedTaskDetails() throws Exception {
+        final AtomicReference<String> result = new AtomicReference<String>();
+
+        Thread bg = new Thread(new Runnable() {
+            public void run() {
+                try {
+                    // Expect "spawned child" to tell us it's blocking 
+                    if (!e.nowWaitingLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
+                        result.set("took too long for spawnchild's sub-task to be waiting");
+                        return;
+                    }
+
+                    // Expect spawned task to be have been tagged with entity
+                    ExecutionManager em = e.getManagementContext().getExecutionManager();
+                    Task<?> subtask = Iterables.find(BrooklynTaskTags.getTasksInEntityContext(em, e), new Predicate<Task<?>>() {
+                        public boolean apply(Task<?> input) {
+                            return "SpawnedChildName".equals(input.getDisplayName());
+                        }
+                    });
+                    
+                    // Expect spawned task to haev correct "blocking details"
+                    try {
+                        String status = subtask.getStatusDetail(true);
+                        log.info("subtask task says:\n"+status);
+                        if (!status.contains("spawned child blocking details")) {
+                            result.set("Status not in expected format: doesn't contain blocking details phrase 'spawned child blocking details'\n"+status);
+                            return;
+                        }
+                    } finally {
+                        e.continueFromWaitingLatch.countDown();
+                    }
+                } catch (Throwable t) {
+                    log.warn("Failure: "+t, t);
+                    result.set("Failure: "+t);
+                }
+            }});
+        bg.start();
+    
+        e.invoke(MyEntityImpl.SPAWN_CHILD, ImmutableMap.<String,Object>of())
+                .get(TIMEOUT, TimeUnit.MILLISECONDS);
+        
+        bg.join(TIMEOUT*2);
+        assertFalse(bg.isAlive());
+        
+        String problem = result.get();
+        if (problem!=null) fail(problem);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorMetadataTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorMetadataTest.java b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorMetadataTest.java
new file mode 100644
index 0000000..1f1be85
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorMetadataTest.java
@@ -0,0 +1,166 @@
+/*
+ * 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.core.effector;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.effector.ParameterType;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.annotation.EffectorParam;
+import org.apache.brooklyn.core.effector.BasicParameterType;
+import org.apache.brooklyn.core.effector.Effectors;
+import org.apache.brooklyn.core.effector.MethodEffector;
+import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.mgmt.internal.EffectorUtils;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Test the operation of the {@link Effector} implementations.
+ *
+ * TODO clarify test purpose
+ */
+public class EffectorMetadataTest extends BrooklynAppUnitTestSupport {
+    
+    private MyAnnotatedEntity e1;
+    private MyOverridingEntity e2;
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        e1 = app.createAndManageChild(EntitySpec.create(MyAnnotatedEntity.class));
+        e2 = app.createAndManageChild(EntitySpec.create(MyOverridingEntity.class));
+    }
+
+    @Test
+    public void testEffectorMetaDataFromAnnotationsWithConstant() {
+        Effector<?> effector = EffectorUtils.findEffectorDeclared(e1, "effWithNewAnnotation").get();
+        Assert.assertTrue(Effectors.sameSignature(effector, MyAnnotatedEntity.EFF_WITH_NEW_ANNOTATION));
+        assertEquals(effector.getName(), "effWithNewAnnotation");
+        assertEquals(effector.getDescription(), "my effector description");
+        assertEquals(effector.getReturnType(), String.class);
+        assertParametersEqual(
+                effector.getParameters(), 
+                ImmutableList.<ParameterType<?>>of(
+                        new BasicParameterType<String>("param1", String.class, "my param description", "my default val")));
+    }
+
+    @Test
+    public void testEffectorMetaDataFromAnnotationsWithoutConstant() {
+        Effector<?> effector = EffectorUtils.findEffectorDeclared(e1, "effWithAnnotationButNoConstant").get();
+        assertEquals(effector.getName(), "effWithAnnotationButNoConstant");
+        assertEquals(effector.getDescription(), "my effector description");
+        assertEquals(effector.getReturnType(), String.class);
+        assertParametersEqual(
+                effector.getParameters(), 
+                ImmutableList.<ParameterType<?>>of(
+                        new BasicParameterType<String>("param1", String.class, "my param description", "my default val")));
+    }
+
+    @SuppressWarnings("rawtypes")
+    @Test
+    public void testEffectorMetaDataFromOverriddenMethod() {
+        // Overridden with new annotations
+        Effector<?> startEffector = EffectorUtils.findEffectorDeclared(e2, "start").get();
+        assertEquals(startEffector.getName(), "start");
+        assertEquals(startEffector.getDescription(), "My overridden start description");
+        assertEquals(startEffector.getReturnType(), void.class);
+        assertParametersEqual(
+                startEffector.getParameters(), 
+                ImmutableList.<ParameterType<?>>of(
+                        new BasicParameterType<Collection>("locations", Collection.class, "my overridden param description", null)));
+    }
+
+    private void assertParametersEqual(List<ParameterType<?>> actuals, List<ParameterType<?>> expecteds) {
+        assertEquals(actuals.size(), expecteds.size(), "actual="+actuals);
+        for (int i = 0; i < actuals.size(); i++) {
+            ParameterType<?> actual = actuals.get(i);
+            ParameterType<?> expected = expecteds.get(i);
+            assertParameterEqual(actual, expected);
+        }
+    }
+    
+    private void assertParameterEqual(ParameterType<?> actual, ParameterType<?> expected) {
+        assertEquals(actual.getName(), expected.getName(), "actual="+actual);
+        assertEquals(actual.getDescription(), expected.getDescription(), "actual="+actual);
+        assertEquals(actual.getParameterClass(), expected.getParameterClass(), "actual="+actual);
+        assertEquals(actual.getParameterClassName(), expected.getParameterClassName(), "actual="+actual);
+    }
+
+    @ImplementedBy(MyAnnotatedEntityImpl.class)
+    public interface MyAnnotatedEntity extends Entity {
+        static MethodEffector<String> EFF_WITH_NEW_ANNOTATION = new MethodEffector<String>(MyAnnotatedEntity.class, "effWithNewAnnotation");
+
+        @org.apache.brooklyn.core.annotation.Effector(description="my effector description")
+        public String effWithNewAnnotation(
+                @EffectorParam(name="param1", defaultValue="my default val", description="my param description") String param1);
+        
+        @org.apache.brooklyn.core.annotation.Effector(description="my effector description")
+        public String effWithAnnotationButNoConstant(
+                @EffectorParam(name="param1", defaultValue="my default val", description="my param description") String param1);
+    }
+    
+    public static class MyAnnotatedEntityImpl extends AbstractEntity implements MyAnnotatedEntity {
+        @Override
+        public String effWithNewAnnotation(String param1) {
+            return param1;
+        }
+
+        @Override
+        public String effWithAnnotationButNoConstant(String param1) {
+            return param1;
+        }
+    }
+    
+    @ImplementedBy(MyOverridingEntityImpl.class)
+    public interface MyOverridingEntity extends Entity, Startable {
+        org.apache.brooklyn.api.effector.Effector<Void> START = Effectors.effector(Startable.START)
+            .description("My overridden start description")
+            .parameter(Collection.class, "locations", "my overridden param description")
+            .build();
+    }
+
+    public static class MyOverridingEntityImpl extends AbstractEntity implements MyOverridingEntity {
+
+        @Override
+        public void restart() {
+        }
+
+        @Override
+        public void start(Collection<? extends Location> locations2) {
+        }
+
+        @Override
+        public void stop() {
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiGroovyTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiGroovyTest.groovy b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiGroovyTest.groovy
new file mode 100644
index 0000000..5dd776e
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiGroovyTest.groovy
@@ -0,0 +1,182 @@
+/*
+ * 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.core.effector
+
+import static org.testng.Assert.*
+
+import org.apache.brooklyn.api.effector.Effector
+import org.apache.brooklyn.api.entity.Entity
+import org.apache.brooklyn.api.entity.EntitySpec
+import org.apache.brooklyn.api.entity.ImplementedBy
+import org.apache.brooklyn.api.mgmt.ManagementContext
+import org.apache.brooklyn.api.mgmt.Task
+import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.core.mgmt.internal.EffectorUtils
+import org.apache.brooklyn.core.test.entity.TestApplication
+import org.apache.brooklyn.core.annotation.EffectorParam
+import org.apache.brooklyn.core.effector.BasicParameterType;
+import org.apache.brooklyn.core.effector.ExplicitEffector;
+import org.apache.brooklyn.core.effector.MethodEffector;
+import org.apache.brooklyn.core.entity.AbstractEntity
+import org.apache.brooklyn.core.entity.Entities
+import org.apache.brooklyn.core.entity.trait.Startable
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+import org.testng.annotations.AfterMethod
+import org.testng.annotations.BeforeMethod
+import org.testng.annotations.Test
+
+/**
+ * Test the operation of the {@link Effector} implementations.
+ *
+ * TODO clarify test purpose
+ */
+public class EffectorSayHiGroovyTest {
+    private static final Logger log = LoggerFactory.getLogger(EffectorSayHiTest.class);
+
+    private TestApplication app;
+    private MyEntity e;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() {
+        app = TestApplication.Factory.newManagedInstanceForTests();
+        e = app.createAndManageChild(EntitySpec.create(MyEntity.class));
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+
+    @Test
+    public void testFindEffectors() {
+        assertEquals("sayHi1", e.SAY_HI_1.getName());
+        assertEquals(["name", "greeting"], e.SAY_HI_1.getParameters()[0..1]*.getName());
+        assertEquals("says hello", e.SAY_HI_1.getDescription());
+
+		assertEquals("sayHi1", e.SAY_HI_1_ALT.getName());
+		assertEquals(["name", "greeting"], e.SAY_HI_1_ALT.getParameters()[0..1]*.getName());
+		assertEquals("says hello", e.SAY_HI_1_ALT.getDescription());
+
+		assertEquals("sayHi2", e.SAY_HI_2.getName());
+		assertEquals(["name", "greeting"], e.SAY_HI_2.getParameters()[0..1]*.getName());
+		assertEquals("says hello", e.SAY_HI_2.getDescription());
+    }
+
+    @Test
+    public void testFindTraitEffectors() {
+        assertEquals("locations", Startable.START.getParameters()[0].getName());
+    }
+
+    @Test
+    public void testInvokeEffectorMethod1BypassInterception() {
+        String name = "sayHi1"
+        def args = ["Bob", "hello"] as Object[]
+
+        //try the alt syntax recommended from web
+        def metaMethod = e.metaClass.getMetaMethod(name, args)
+        if (metaMethod==null)
+            throw new IllegalArgumentException("Invalid arguments (no method found) for method $name: "+args);
+        assertEquals("hello Bob", metaMethod.invoke(e, args))
+    }
+
+    @Test
+    public void testInvokeEffectorMethod2BypassInterception() {
+        String name = "sayHi2"
+        def args = ["Bob", "hello"] as Object[]
+        assertEquals("hello Bob", e.metaClass.invokeMethod(e, name, args))
+    }
+
+    @Test
+    public void testInvokeEffectors1() {
+        assertEquals("hi Bob", e.sayHi1("Bob", "hi"))
+
+        assertEquals("hello Bob", e.SAY_HI_1.call(e, [name:"Bob"]) )
+        assertEquals("hello Bob", e.invoke(e.SAY_HI_1, [name:"Bob"]).get() );
+
+		assertEquals("hello Bob", e.SAY_HI_1_ALT.call(e, [name:"Bob"]) )
+    }
+
+    @Test
+    public void testInvokeEffectors2() {
+        assertEquals("hi Bob", e.sayHi2("Bob", "hi"))
+
+        assertEquals("hello Bob", e.SAY_HI_2.call(e, [name:"Bob"]) )
+        assertEquals("hello Bob", e.invoke(e.SAY_HI_2, [name:"Bob"]).get() );
+        
+    }
+
+    @Test
+    public void testCanRetrieveTaskForEffector() {
+        e.sayHi2("Bob", "hi")
+
+        ManagementContext managementContext = e.getManagementContext()
+
+        Set<Task> tasks = managementContext.getExecutionManager().getTasksWithAllTags([
+            BrooklynTaskTags.tagForContextEntity(e),"EFFECTOR"])
+        assertEquals(tasks.size(), 1)
+        assertTrue(tasks.iterator().next().getDescription().contains("sayHi2"))
+    }
+}
+public interface CanSayHi {
+	//prefer following simple groovy syntax
+	static Effector<String> SAY_HI_1 = new MethodEffector<String>(CanSayHi.&sayHi1);
+	//slightly longer-winded pojo also supported
+	static Effector<String> SAY_HI_1_ALT = new MethodEffector<String>(CanSayHi.class, "sayHi1");
+
+	@org.apache.brooklyn.core.annotation.Effector(description="says hello")
+	public String sayHi1(
+		@EffectorParam(name="name") String name,
+		@EffectorParam(name="greeting", defaultValue="hello", description="what to say") String greeting);
+
+	//finally there is a way to provide a class/closure if needed or preferred for some odd reason
+	static Effector<String> SAY_HI_2 =
+
+		//groovy 1.8.2 balks at runtime during getCallSiteArray (bug 5122) if we use anonymous inner class
+//	  new ExplicitEffector<CanSayHi,String>(
+//			"sayHi2", String.class, [
+//					[ "name", String.class, "person to say hi to" ] as BasicParameterType<String>,
+//					[ "greeting", String.class, "what to say as greeting", "hello" ] as BasicParameterType<String>
+//				],
+//			"says hello to a person") {
+//		public String invokeEffector(CanSayHi e, Map m) {
+//			e.sayHi2(m)
+//		}
+//	};
+	//following is a workaround, not greatly enamoured of it... but MethodEffector is generally preferred anyway
+		ExplicitEffector.create("sayHi2", String.class, [
+					new BasicParameterType<String>("name", String.class, "person to say hi to"),
+					new BasicParameterType<String>("greeting", String.class, "what to say as greeting", "hello")
+				],
+			"says hello", { e, m ->
+                def args = EffectorUtils.prepareArgsForEffector(SAY_HI_2, m);
+                e.sayHi2(args[0], args[1]) })
+
+	public String sayHi2(String name, String greeting);
+
+}
+
+@ImplementedBy(MyEntityImpl.class)
+public interface MyEntity extends Entity, CanSayHi {
+}
+
+public class MyEntityImpl extends AbstractEntity implements MyEntity {
+    public String sayHi1(String name, String greeting) { "$greeting $name" }
+	public String sayHi2(String name, String greeting) { "$greeting $name" }
+}


[36/36] incubator-brooklyn git commit: This closes #854

Posted by he...@apache.org.
This closes #854


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

Branch: refs/heads/master
Commit: 147f9ec446a6bb59c8550e62eacc5c0970b73227
Parents: 9e80f33 6f15e8a
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Aug 19 23:52:04 2015 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Aug 19 23:52:04 2015 +0100

----------------------------------------------------------------------
 .../apache/brooklyn/api/entity/Application.java |    2 +-
 .../org/apache/brooklyn/api/entity/Entity.java  |    8 +-
 .../brooklyn/api/entity/EntityInitializer.java  |    2 -
 .../apache/brooklyn/api/entity/EntityLocal.java |  176 ++
 .../api/entity/drivers/EntityDriver.java        |    2 +-
 .../brooklyn/api/internal/EntityLocal.java      |  178 --
 .../BrooklynClassLoadingContext.java            |   50 -
 .../api/mgmt/rebind/RebindExceptionHandler.java |    2 +-
 .../core/BrooklynFeatureEnablement.java         |  209 +++
 .../apache/brooklyn/core/BrooklynLogging.java   |    2 +-
 .../brooklyn/core/annotation/Effector.java      |   33 +
 .../brooklyn/core/annotation/EffectorParam.java |   42 +
 .../catalog/internal/BasicBrooklynCatalog.java  |   10 +-
 .../catalog/internal/CatalogClasspathDo.java    |    2 +-
 .../core/catalog/internal/CatalogUtils.java     |    4 +-
 .../brooklyn/core/config/BasicConfigKey.java    |    2 +-
 .../apache/brooklyn/core/config/ConfigKeys.java |    8 +-
 .../config/internal/AbstractConfigMapImpl.java  |    2 +-
 .../core/config/render/RendererHints.java       |    2 +-
 .../core/effector/AbstractEffector.java         |   90 +
 .../core/effector/AddChildrenEffector.java      |  117 ++
 .../brooklyn/core/effector/AddEffector.java     |  116 ++
 .../brooklyn/core/effector/AddSensor.java       |  126 ++
 .../core/effector/BasicParameterType.java       |  116 ++
 .../brooklyn/core/effector/EffectorAndBody.java |   60 +
 .../brooklyn/core/effector/EffectorBase.java    |  106 ++
 .../brooklyn/core/effector/EffectorBody.java    |  100 +
 .../brooklyn/core/effector/EffectorTasks.java   |  229 +++
 .../core/effector/EffectorWithBody.java         |   32 +
 .../brooklyn/core/effector/Effectors.java       |  202 ++
 .../core/effector/ExplicitEffector.java         |   74 +
 .../brooklyn/core/effector/MethodEffector.java  |  180 ++
 .../core/effector/ssh/SshEffectorTasks.java     |  335 ++++
 .../core/enricher/AbstractEnricher.java         |  115 ++
 .../core/enricher/EnricherDynamicType.java      |   43 +
 .../core/enricher/EnricherTypeSnapshot.java     |   39 +
 .../core/entity/AbstractApplication.java        |  264 +++
 .../brooklyn/core/entity/AbstractEntity.java    | 1739 ++++++++++++++++++
 .../apache/brooklyn/core/entity/Attributes.java |  169 ++
 .../core/entity/BrooklynConfigKeys.java         |  188 ++
 .../apache/brooklyn/core/entity/Entities.java   | 1108 +++++++++++
 .../brooklyn/core/entity/EntityAdjuncts.java    |   70 +
 .../core/entity/EntityAndAttribute.java         |  107 ++
 .../brooklyn/core/entity/EntityDynamicType.java |  339 ++++
 .../brooklyn/core/entity/EntityFunctions.java   |  153 ++
 .../core/entity/EntityInitializers.java         |   49 +
 .../brooklyn/core/entity/EntityInternal.java    |  201 ++
 .../brooklyn/core/entity/EntityPredicates.java  |  451 +++++
 .../brooklyn/core/entity/EntitySuppliers.java   |   47 +
 .../brooklyn/core/entity/EntityTasks.java       |   81 +
 .../core/entity/EntityTypeSnapshot.java         |  126 ++
 .../brooklyn/core/entity/EntityTypes.java       |   28 +
 .../core/entity/StartableApplication.java       |   25 +
 .../drivers/BasicEntityDriverManager.java       |   56 +
 .../drivers/ReflectiveEntityDriverFactory.java  |  277 +++
 .../drivers/RegistryEntityDriverFactory.java    |  127 ++
 .../downloads/BasicDownloadRequirement.java     |   85 +
 .../downloads/BasicDownloadResolver.java        |   66 +
 .../drivers/downloads/BasicDownloadTargets.java |  121 ++
 .../downloads/BasicDownloadsManager.java        |  161 ++
 .../DownloadProducerFromCloudsoftRepo.java      |   83 +
 .../DownloadProducerFromLocalRepo.java          |   84 +
 .../DownloadProducerFromProperties.java         |  344 ++++
 .../DownloadProducerFromUrlAttribute.java       |   63 +
 .../drivers/downloads/DownloadSubstituters.java |  172 ++
 .../drivers/downloads/FilenameProducers.java    |   64 +
 .../AbstractConfigurableEntityFactory.java      |   82 +
 .../core/entity/factory/ApplicationBuilder.java |  247 +++
 .../factory/BasicConfigurableEntityFactory.java |   75 +
 .../entity/factory/ClosureEntityFactory.java    |   53 +
 .../factory/ConfigurableEntityFactory.java      |   33 +
 ...figurableEntityFactoryFromEntityFactory.java |   45 +
 .../core/entity/factory/EntityFactory.java      |   32 +
 .../factory/EntityFactoryForLocation.java       |   30 +
 .../internal/ConfigMapViewWithStringKeys.java   |  130 ++
 .../core/entity/internal/EntityConfigMap.java   |  306 +++
 .../internal/EntityTransientCopyInternal.java   |  121 ++
 .../core/entity/lifecycle/Lifecycle.java        |  185 ++
 .../core/entity/lifecycle/PolicyDescriptor.java |   68 +
 .../core/entity/lifecycle/QuorumCheck.java      |  108 ++
 .../entity/lifecycle/ServiceStateLogic.java     |  639 +++++++
 .../brooklyn/core/entity/trait/Changeable.java  |   35 +
 .../core/entity/trait/MemberReplaceable.java    |   45 +
 .../brooklyn/core/entity/trait/Resizable.java   |   50 +
 .../brooklyn/core/entity/trait/Startable.java   |  123 ++
 .../core/entity/trait/StartableMethods.java     |  125 ++
 .../apache/brooklyn/core/feed/AbstractFeed.java |  240 +++
 .../core/feed/AttributePollHandler.java         |  248 +++
 .../brooklyn/core/feed/ConfigToAttributes.java  |   59 +
 .../core/feed/DelegatingPollHandler.java        |   96 +
 .../apache/brooklyn/core/feed/FeedConfig.java   |  297 +++
 .../apache/brooklyn/core/feed/PollConfig.java   |   85 +
 .../apache/brooklyn/core/feed/PollHandler.java  |   38 +
 .../org/apache/brooklyn/core/feed/Poller.java   |  205 +++
 .../internal/BrooklynFeatureEnablement.java     |  208 ---
 .../core/internal/BrooklynInitialization.java   |    2 +-
 .../core/location/AbstractLocation.java         |  709 +++++++
 .../core/location/AbstractLocationResolver.java |  188 ++
 .../AggregatingMachineProvisioningLocation.java |  141 ++
 .../core/location/BasicHardwareDetails.java     |   56 +
 .../core/location/BasicLocationDefinition.java  |   85 +
 .../core/location/BasicLocationRegistry.java    |  489 +++++
 .../core/location/BasicMachineDetails.java      |  183 ++
 .../core/location/BasicMachineMetadata.java     |   84 +
 .../brooklyn/core/location/BasicOsDetails.java  |  123 ++
 .../core/location/CatalogLocationResolver.java  |   79 +
 .../location/DefinedLocationByIdResolver.java   |   74 +
 .../location/DeprecatedKeysMappingBuilder.java  |   66 +
 .../core/location/HasSubnetHostname.java        |   32 +
 .../core/location/LocationConfigKeys.java       |   79 +
 .../core/location/LocationConfigUtils.java      |  559 ++++++
 .../core/location/LocationPredicates.java       |  108 ++
 ...ocationPropertiesFromBrooklynProperties.java |  223 +++
 .../brooklyn/core/location/Locations.java       |  160 ++
 .../apache/brooklyn/core/location/Machines.java |  191 ++
 .../core/location/NamedLocationResolver.java    |   97 +
 .../brooklyn/core/location/PortRanges.java      |  257 +++
 .../core/location/RegistryLocationResolver.java |   42 +
 .../core/location/SupportsPortForwarding.java   |   39 +
 .../location/access/BrooklynAccessUtils.java    |  154 ++
 .../location/access/PortForwardManager.java     |  328 ++++
 .../access/PortForwardManagerAuthority.java     |   46 +
 .../access/PortForwardManagerClient.java        |  405 ++++
 .../location/access/PortForwardManagerImpl.java |  505 +++++
 .../PortForwardManagerLocationResolver.java     |   89 +
 .../core/location/access/PortMapping.java       |  101 +
 .../AbstractAvailabilityZoneExtension.java      |   82 +
 ...bstractCloudMachineProvisioningLocation.java |   97 +
 .../cloud/AvailabilityZoneExtension.java        |   54 +
 .../location/cloud/CloudLocationConfig.java     |  116 ++
 .../cloud/names/AbstractCloudMachineNamer.java  |  150 ++
 .../cloud/names/BasicCloudMachineNamer.java     |   91 +
 .../location/cloud/names/CloudMachineNamer.java |   61 +
 .../cloud/names/CustomMachineNamer.java         |   72 +
 .../core/location/dynamic/DynamicLocation.java  |   50 +
 .../core/location/dynamic/LocationOwner.java    |   85 +
 .../location/geo/GeoBytesHostGeoLookup.java     |  104 ++
 .../core/location/geo/HasHostGeoInfo.java       |   25 +
 .../brooklyn/core/location/geo/HostGeoInfo.java |  205 +++
 .../core/location/geo/HostGeoLookup.java        |   27 +
 .../location/geo/LocalhostExternalIpLoader.java |  177 ++
 .../location/geo/MaxMind2HostGeoLookup.java     |  114 ++
 .../core/location/geo/UtraceHostGeoLookup.java  |  209 +++
 .../location/internal/LocationDynamicType.java  |   40 +
 .../location/internal/LocationInternal.java     |   93 +
 .../location/internal/LocationTypeSnapshot.java |   40 +
 .../core/mgmt/EntityManagementUtils.java        |   10 +-
 .../AbstractBrooklynClassLoadingContext.java    |    1 -
 .../BrooklynClassLoadingContext.java            |   50 +
 .../BrooklynClassLoadingContextSequential.java  |    1 -
 ...ssLoaderFromBrooklynClassLoadingContext.java |    2 -
 .../core/mgmt/entitlement/Entitlements.java     |    2 +-
 .../mgmt/ha/HighAvailabilityManagerImpl.java    |    4 +-
 .../internal/AbstractManagementContext.java     |   14 +-
 .../mgmt/internal/BrooklynGarbageCollector.java |    2 +-
 .../mgmt/internal/BrooklynShutdownHooks.java    |    6 +-
 .../core/mgmt/internal/EffectorUtils.java       |    6 +-
 .../mgmt/internal/EntityManagementSupport.java  |    6 +-
 .../core/mgmt/internal/LocalEntityManager.java  |   10 +-
 .../mgmt/internal/LocalLocationManager.java     |    6 +-
 .../mgmt/internal/LocalManagementContext.java   |    6 +-
 .../mgmt/internal/LocalSubscriptionManager.java |    2 +-
 .../core/mgmt/internal/LocalUsageManager.java   |   65 +-
 .../internal/ManagementContextInternal.java     |    1 +
 .../NonDeploymentManagementContext.java         |    3 +-
 .../internal/NonDeploymentUsageManager.java     |   15 +-
 .../core/mgmt/internal/UsageListener.java       |  103 --
 .../core/mgmt/internal/UsageManager.java        |  165 --
 .../mgmt/persist/BrooklynPersistenceUtils.java  |    4 +-
 .../core/mgmt/persist/XmlMementoSerializer.java |   12 +-
 .../rebind/ActivePartialRebindIteration.java    |    2 +-
 .../mgmt/rebind/BasicEnricherRebindSupport.java |    2 +-
 .../mgmt/rebind/BasicEntityRebindSupport.java   |   12 +-
 .../mgmt/rebind/BasicFeedRebindSupport.java     |    2 +-
 .../mgmt/rebind/BasicLocationRebindSupport.java |    2 +-
 .../mgmt/rebind/BasicPolicyRebindSupport.java   |    2 +-
 .../rebind/ImmediateDeltaChangeListener.java    |    2 +-
 .../mgmt/rebind/InitialFullRebindIteration.java |    2 +-
 .../rebind/PeriodicDeltaChangeListener.java     |    4 +-
 .../mgmt/rebind/RebindExceptionHandlerImpl.java |    2 +-
 .../core/mgmt/rebind/RebindIteration.java       |   20 +-
 .../core/mgmt/rebind/RebindManagerImpl.java     |    6 +-
 .../core/mgmt/rebind/dto/AbstractMemento.java   |    2 +-
 .../mgmt/rebind/dto/BasicEnricherMemento.java   |    2 +-
 .../mgmt/rebind/dto/BasicEntityMemento.java     |    4 +-
 .../core/mgmt/rebind/dto/BasicFeedMemento.java  |    2 +-
 .../mgmt/rebind/dto/BasicLocationMemento.java   |    2 +-
 .../mgmt/rebind/dto/BasicPolicyMemento.java     |    2 +-
 .../mgmt/rebind/dto/MementosGenerators.java     |   12 +-
 .../core/mgmt/usage/ApplicationUsage.java       |    2 +-
 .../brooklyn/core/mgmt/usage/LocationUsage.java |    2 +-
 .../brooklyn/core/mgmt/usage/UsageListener.java |  103 ++
 .../brooklyn/core/mgmt/usage/UsageManager.java  |  165 ++
 .../core/objs/AbstractBrooklynObject.java       |    2 +-
 .../core/objs/AbstractEntityAdjunct.java        |   10 +-
 .../brooklyn/core/objs/AdjunctConfigMap.java    |    6 +-
 .../brooklyn/core/objs/BrooklynTypes.java       |    6 +-
 .../core/objs/proxy/EntityProxyImpl.java        |   12 +-
 .../core/objs/proxy/InternalEntityFactory.java  |   12 +-
 .../objs/proxy/InternalLocationFactory.java     |    4 +-
 .../core/objs/proxy/InternalPolicyFactory.java  |    6 +-
 .../brooklyn/core/policy/AbstractPolicy.java    |  119 ++
 .../apache/brooklyn/core/policy/Policies.java   |   73 +
 .../brooklyn/core/policy/PolicyDynamicType.java |   43 +
 .../core/policy/PolicyTypeSnapshot.java         |   39 +
 .../brooklyn/core/sensor/AttributeMap.java      |  202 ++
 .../sensor/AttributeSensorAndConfigKey.java     |  147 ++
 .../core/sensor/BasicAttributeSensor.java       |   62 +
 .../BasicAttributeSensorAndConfigKey.java       |  114 ++
 .../core/sensor/BasicNotificationSensor.java    |   36 +
 .../brooklyn/core/sensor/BasicSensor.java       |  114 ++
 .../brooklyn/core/sensor/BasicSensorEvent.java  |  112 ++
 .../core/sensor/DependentConfiguration.java     |  823 +++++++++
 .../brooklyn/core/sensor/HttpRequestSensor.java |   96 +
 .../sensor/PortAttributeSensorAndConfigKey.java |  141 ++
 .../apache/brooklyn/core/sensor/Sensors.java    |  164 ++
 .../brooklyn/core/sensor/StaticSensor.java      |   72 +
 ...platedStringAttributeSensorAndConfigKey.java |   66 +
 .../core/server/entity/BrooklynMetrics.java     |    4 +-
 .../core/server/entity/BrooklynMetricsImpl.java |    2 +-
 .../effector/core/AbstractEffector.java         |   90 -
 .../effector/core/AddChildrenEffector.java      |  117 --
 .../brooklyn/effector/core/AddEffector.java     |  116 --
 .../brooklyn/effector/core/AddSensor.java       |  126 --
 .../effector/core/BasicParameterType.java       |  116 --
 .../brooklyn/effector/core/EffectorAndBody.java |   60 -
 .../brooklyn/effector/core/EffectorBase.java    |  106 --
 .../brooklyn/effector/core/EffectorBody.java    |  100 -
 .../brooklyn/effector/core/EffectorTasks.java   |  229 ---
 .../effector/core/EffectorWithBody.java         |   32 -
 .../brooklyn/effector/core/Effectors.java       |  202 --
 .../effector/core/ExplicitEffector.java         |   74 -
 .../brooklyn/effector/core/MethodEffector.java  |  180 --
 .../stock/AbstractAggregatingEnricher.java      |  174 ++
 .../enricher/stock/AbstractAggregator.java      |  238 +++
 .../stock/AbstractMultipleSensorAggregator.java |  169 ++
 .../enricher/stock/AbstractTransformer.java     |  101 +
 .../stock/AbstractTransformingEnricher.java     |   38 +
 .../stock/AbstractTypeTransformingEnricher.java |   68 +
 .../brooklyn/enricher/stock/AddingEnricher.java |  107 ++
 .../brooklyn/enricher/stock/Aggregator.java     |  222 +++
 .../brooklyn/enricher/stock/Combiner.java       |  138 ++
 .../stock/CustomAggregatingEnricher.java        |  320 ++++
 .../brooklyn/enricher/stock/Enrichers.java      |  825 +++++++++
 .../apache/brooklyn/enricher/stock/Joiner.java  |  127 ++
 .../brooklyn/enricher/stock/Propagator.java     |  201 ++
 .../stock/SensorPropagatingEnricher.java        |  181 ++
 .../stock/SensorTransformingEnricher.java       |  106 ++
 .../brooklyn/enricher/stock/Transformer.java    |  103 ++
 .../brooklyn/enricher/stock/UpdatingMap.java    |  159 ++
 .../YamlRollingTimeWindowMeanEnricher.java      |  178 ++
 .../stock/YamlTimeWeightedDeltaEnricher.java    |   83 +
 .../brooklyn/entity/annotation/Effector.java    |   33 -
 .../entity/annotation/EffectorParam.java        |   42 -
 .../entity/core/AbstractApplication.java        |  264 ---
 .../brooklyn/entity/core/AbstractEntity.java    | 1739 ------------------
 .../apache/brooklyn/entity/core/Attributes.java |  169 --
 .../entity/core/BrooklynConfigKeys.java         |  188 --
 .../apache/brooklyn/entity/core/Entities.java   | 1108 -----------
 .../brooklyn/entity/core/EntityAdjuncts.java    |   70 -
 .../entity/core/EntityAndAttribute.java         |  107 --
 .../brooklyn/entity/core/EntityDynamicType.java |  339 ----
 .../brooklyn/entity/core/EntityFunctions.java   |  153 --
 .../entity/core/EntityInitializers.java         |   49 -
 .../brooklyn/entity/core/EntityInternal.java    |  201 --
 .../brooklyn/entity/core/EntityPredicates.java  |  451 -----
 .../brooklyn/entity/core/EntitySuppliers.java   |   47 -
 .../brooklyn/entity/core/EntityTasks.java       |   81 -
 .../entity/core/EntityTypeSnapshot.java         |  126 --
 .../brooklyn/entity/core/EntityTypes.java       |   28 -
 .../entity/core/StartableApplication.java       |   25 -
 .../internal/ConfigMapViewWithStringKeys.java   |  130 --
 .../entity/core/internal/EntityConfigMap.java   |  306 ---
 .../internal/EntityTransientCopyInternal.java   |  121 --
 .../drivers/BasicEntityDriverManager.java       |   56 -
 .../drivers/ReflectiveEntityDriverFactory.java  |  277 ---
 .../drivers/RegistryEntityDriverFactory.java    |  127 --
 .../downloads/BasicDownloadRequirement.java     |   85 -
 .../downloads/BasicDownloadResolver.java        |   66 -
 .../drivers/downloads/BasicDownloadTargets.java |  121 --
 .../downloads/BasicDownloadsManager.java        |  161 --
 .../DownloadProducerFromCloudsoftRepo.java      |   83 -
 .../DownloadProducerFromLocalRepo.java          |   84 -
 .../DownloadProducerFromProperties.java         |  344 ----
 .../DownloadProducerFromUrlAttribute.java       |   63 -
 .../drivers/downloads/DownloadSubstituters.java |  172 --
 .../drivers/downloads/FilenameProducers.java    |   64 -
 .../AbstractConfigurableEntityFactory.java      |   82 -
 .../entity/factory/ApplicationBuilder.java      |  247 ---
 .../factory/BasicConfigurableEntityFactory.java |   75 -
 .../entity/factory/ClosureEntityFactory.java    |   53 -
 .../factory/ConfigurableEntityFactory.java      |   33 -
 ...figurableEntityFactoryFromEntityFactory.java |   45 -
 .../brooklyn/entity/factory/EntityFactory.java  |   32 -
 .../factory/EntityFactoryForLocation.java       |   30 -
 .../brooklyn/entity/group/AbstractGroup.java    |    6 +-
 .../entity/group/AbstractGroupImpl.java         |   10 +-
 .../group/AbstractMembershipTrackingPolicy.java |    6 +-
 .../apache/brooklyn/entity/group/Cluster.java   |    4 +-
 .../brooklyn/entity/group/DynamicCluster.java   |   20 +-
 .../entity/group/DynamicClusterImpl.java        |   26 +-
 .../brooklyn/entity/group/DynamicFabric.java    |   10 +-
 .../entity/group/DynamicFabricImpl.java         |   28 +-
 .../brooklyn/entity/group/DynamicGroup.java     |    8 +-
 .../brooklyn/entity/group/DynamicGroupImpl.java |    2 +-
 .../entity/group/DynamicMultiGroup.java         |    2 +-
 .../entity/group/DynamicMultiGroupImpl.java     |    6 +-
 .../entity/group/DynamicRegionsFabric.java      |    6 +-
 .../entity/group/DynamicRegionsFabricImpl.java  |    6 +-
 .../brooklyn/entity/group/QuarantineGroup.java  |    4 +-
 .../entity/group/QuarantineGroupImpl.java       |    8 +-
 .../BalancingNodePlacementStrategy.java         |    2 +-
 .../brooklyn/entity/lifecycle/Lifecycle.java    |  185 --
 .../entity/lifecycle/PolicyDescriptor.java      |   68 -
 .../brooklyn/entity/lifecycle/QuorumCheck.java  |  108 --
 .../entity/lifecycle/ServiceStateLogic.java     |  639 -------
 .../brooklyn/entity/stock/BasicApplication.java |    2 +-
 .../entity/stock/BasicApplicationImpl.java      |    2 +-
 .../brooklyn/entity/stock/BasicEntityImpl.java  |    2 +-
 .../brooklyn/entity/stock/BasicStartable.java   |    4 +-
 .../entity/stock/BasicStartableImpl.java        |   18 +-
 .../brooklyn/entity/stock/DataEntity.java       |    2 +-
 .../brooklyn/entity/stock/DataEntityImpl.java   |    6 +-
 .../brooklyn/entity/stock/DelegateEntity.java   |    4 +-
 .../entity/stock/DelegateEntityImpl.java        |    4 +-
 .../entity/stock/EffectorStartableImpl.java     |    8 +-
 .../brooklyn/entity/trait/Changeable.java       |   35 -
 .../entity/trait/MemberReplaceable.java         |   45 -
 .../apache/brooklyn/entity/trait/Resizable.java |   50 -
 .../apache/brooklyn/entity/trait/Startable.java |  123 --
 .../brooklyn/entity/trait/StartableMethods.java |  125 --
 .../brooklyn/feed/function/FunctionFeed.java    |  208 +++
 .../feed/function/FunctionPollConfig.java       |  111 ++
 .../org/apache/brooklyn/feed/http/HttpFeed.java |  382 ++++
 .../brooklyn/feed/http/HttpPollConfig.java      |  160 ++
 .../brooklyn/feed/http/HttpPollValue.java       |   40 +
 .../apache/brooklyn/feed/http/HttpPolls.java    |   39 +
 .../brooklyn/feed/http/HttpValueFunctions.java  |  154 ++
 .../brooklyn/feed/http/JsonFunctions.java       |  235 +++
 .../apache/brooklyn/feed/shell/ShellFeed.java   |  273 +++
 .../brooklyn/feed/shell/ShellPollConfig.java    |  125 ++
 .../org/apache/brooklyn/feed/ssh/SshFeed.java   |  290 +++
 .../apache/brooklyn/feed/ssh/SshPollConfig.java |  142 ++
 .../apache/brooklyn/feed/ssh/SshPollValue.java  |   60 +
 .../brooklyn/feed/ssh/SshValueFunctions.java    |   73 +
 .../windows/WindowsPerformanceCounterFeed.java  |  412 +++++
 .../WindowsPerformanceCounterPollConfig.java    |   53 +
 .../location/access/BrooklynAccessUtils.java    |  154 --
 .../location/access/PortForwardManager.java     |  328 ----
 .../access/PortForwardManagerAuthority.java     |   46 -
 .../access/PortForwardManagerClient.java        |  405 ----
 .../location/access/PortForwardManagerImpl.java |  505 -----
 .../PortForwardManagerLocationResolver.java     |   89 -
 .../brooklyn/location/access/PortMapping.java   |  101 -
 .../location/byon/ByonLocationResolver.java     |    2 +-
 .../FixedListMachineProvisioningLocation.java   |    6 +-
 .../location/byon/HostLocationResolver.java     |    8 +-
 .../byon/SingleMachineLocationResolver.java     |    8 +-
 .../AbstractAvailabilityZoneExtension.java      |   82 -
 ...bstractCloudMachineProvisioningLocation.java |   97 -
 .../cloud/AvailabilityZoneExtension.java        |   54 -
 .../location/cloud/CloudLocationConfig.java     |  116 --
 .../cloud/names/AbstractCloudMachineNamer.java  |  150 --
 .../cloud/names/BasicCloudMachineNamer.java     |   91 -
 .../location/cloud/names/CloudMachineNamer.java |   61 -
 .../cloud/names/CustomMachineNamer.java         |   72 -
 .../location/core/AbstractLocation.java         |  709 -------
 .../location/core/AbstractLocationResolver.java |  188 --
 .../AggregatingMachineProvisioningLocation.java |  141 --
 .../location/core/BasicHardwareDetails.java     |   56 -
 .../location/core/BasicLocationDefinition.java  |   85 -
 .../location/core/BasicLocationRegistry.java    |  489 -----
 .../location/core/BasicMachineDetails.java      |  183 --
 .../location/core/BasicMachineMetadata.java     |   84 -
 .../brooklyn/location/core/BasicOsDetails.java  |  123 --
 .../location/core/CatalogLocationResolver.java  |   79 -
 .../core/DefinedLocationByIdResolver.java       |   74 -
 .../core/DeprecatedKeysMappingBuilder.java      |   66 -
 .../location/core/HasSubnetHostname.java        |   32 -
 .../location/core/LocationConfigKeys.java       |   79 -
 .../location/core/LocationConfigUtils.java      |  559 ------
 .../location/core/LocationPredicates.java       |  108 --
 ...ocationPropertiesFromBrooklynProperties.java |  223 ---
 .../brooklyn/location/core/Locations.java       |  160 --
 .../apache/brooklyn/location/core/Machines.java |  191 --
 .../brooklyn/location/core/MultiLocation.java   |  166 --
 .../location/core/MultiLocationResolver.java    |  145 --
 .../location/core/NamedLocationResolver.java    |   97 -
 .../brooklyn/location/core/PortRanges.java      |  257 ---
 .../location/core/RegistryLocationResolver.java |   42 -
 .../location/core/SupportsPortForwarding.java   |   39 -
 .../core/internal/LocationDynamicType.java      |   40 -
 .../core/internal/LocationInternal.java         |   93 -
 .../core/internal/LocationTypeSnapshot.java     |   40 -
 .../location/dynamic/DynamicLocation.java       |   50 -
 .../location/dynamic/LocationOwner.java         |   85 -
 .../location/geo/GeoBytesHostGeoLookup.java     |  104 --
 .../brooklyn/location/geo/HasHostGeoInfo.java   |   25 -
 .../brooklyn/location/geo/HostGeoInfo.java      |  205 ---
 .../brooklyn/location/geo/HostGeoLookup.java    |   27 -
 .../location/geo/LocalhostExternalIpLoader.java |  177 --
 .../location/geo/MaxMind2HostGeoLookup.java     |  114 --
 .../location/geo/UtraceHostGeoLookup.java       |  209 ---
 .../localhost/LocalhostLocationResolver.java    |    4 +-
 .../LocalhostMachineProvisioningLocation.java   |   12 +-
 ...calhostPropertiesFromBrooklynProperties.java |    2 +-
 .../brooklyn/location/multi/MultiLocation.java  |  167 ++
 .../location/multi/MultiLocationResolver.java   |  149 ++
 .../location/ssh/SshMachineLocation.java        |   16 +-
 .../winrm/AdvertiseWinrmLoginPolicy.java        |    8 +-
 .../location/winrm/WinRmMachineLocation.java    |    4 +-
 .../brooklyn/policy/core/AbstractPolicy.java    |  119 --
 .../policy/core/GeneralPurposePolicy.java       |   36 -
 .../apache/brooklyn/policy/core/Policies.java   |   73 -
 .../brooklyn/policy/core/PolicyDynamicType.java |   43 -
 .../policy/core/PolicyTypeSnapshot.java         |   39 -
 .../brooklyn/sensor/core/AttributeMap.java      |  202 --
 .../core/AttributeSensorAndConfigKey.java       |  147 --
 .../sensor/core/BasicAttributeSensor.java       |   62 -
 .../core/BasicAttributeSensorAndConfigKey.java  |  114 --
 .../sensor/core/BasicNotificationSensor.java    |   36 -
 .../brooklyn/sensor/core/BasicSensor.java       |  114 --
 .../brooklyn/sensor/core/BasicSensorEvent.java  |  112 --
 .../sensor/core/DependentConfiguration.java     |  823 ---------
 .../brooklyn/sensor/core/HttpRequestSensor.java |   96 -
 .../core/PortAttributeSensorAndConfigKey.java   |  141 --
 .../apache/brooklyn/sensor/core/Sensors.java    |  164 --
 .../brooklyn/sensor/core/StaticSensor.java      |   72 -
 ...platedStringAttributeSensorAndConfigKey.java |   66 -
 .../enricher/AbstractAggregatingEnricher.java   |  173 --
 .../sensor/enricher/AbstractAggregator.java     |  237 ---
 .../sensor/enricher/AbstractEnricher.java       |  115 --
 .../AbstractMultipleSensorAggregator.java       |  169 --
 .../sensor/enricher/AbstractTransformer.java    |  100 -
 .../enricher/AbstractTransformingEnricher.java  |   38 -
 .../AbstractTypeTransformingEnricher.java       |   67 -
 .../sensor/enricher/AddingEnricher.java         |  106 --
 .../brooklyn/sensor/enricher/Aggregator.java    |  221 ---
 .../brooklyn/sensor/enricher/Combiner.java      |  137 --
 .../enricher/CustomAggregatingEnricher.java     |  320 ----
 .../sensor/enricher/EnricherDynamicType.java    |   43 -
 .../sensor/enricher/EnricherTypeSnapshot.java   |   39 -
 .../brooklyn/sensor/enricher/Enrichers.java     |  824 ---------
 .../apache/brooklyn/sensor/enricher/Joiner.java |  126 --
 .../brooklyn/sensor/enricher/Propagator.java    |  200 --
 .../enricher/SensorPropagatingEnricher.java     |  180 --
 .../enricher/SensorTransformingEnricher.java    |  106 --
 .../brooklyn/sensor/enricher/Transformer.java   |  103 --
 .../brooklyn/sensor/enricher/UpdatingMap.java   |  158 --
 .../YamlRollingTimeWindowMeanEnricher.java      |  178 --
 .../enricher/YamlTimeWeightedDeltaEnricher.java |   83 -
 .../brooklyn/sensor/feed/AbstractFeed.java      |  240 ---
 .../sensor/feed/AttributePollHandler.java       |  248 ---
 .../sensor/feed/ConfigToAttributes.java         |   59 -
 .../sensor/feed/DelegatingPollHandler.java      |   96 -
 .../apache/brooklyn/sensor/feed/FeedConfig.java |  297 ---
 .../apache/brooklyn/sensor/feed/PollConfig.java |   85 -
 .../brooklyn/sensor/feed/PollHandler.java       |   38 -
 .../org/apache/brooklyn/sensor/feed/Poller.java |  205 ---
 .../sensor/feed/function/FunctionFeed.java      |  208 ---
 .../feed/function/FunctionPollConfig.java       |  111 --
 .../brooklyn/sensor/feed/http/HttpFeed.java     |  382 ----
 .../sensor/feed/http/HttpPollConfig.java        |  160 --
 .../sensor/feed/http/HttpPollValue.java         |   40 -
 .../brooklyn/sensor/feed/http/HttpPolls.java    |   39 -
 .../sensor/feed/http/HttpValueFunctions.java    |  154 --
 .../sensor/feed/http/JsonFunctions.java         |  235 ---
 .../brooklyn/sensor/feed/shell/ShellFeed.java   |  273 ---
 .../sensor/feed/shell/ShellPollConfig.java      |  125 --
 .../brooklyn/sensor/feed/ssh/SshFeed.java       |  290 ---
 .../brooklyn/sensor/feed/ssh/SshPollConfig.java |  142 --
 .../brooklyn/sensor/feed/ssh/SshPollValue.java  |   60 -
 .../sensor/feed/ssh/SshValueFunctions.java      |   73 -
 .../windows/WindowsPerformanceCounterFeed.java  |  412 -----
 .../WindowsPerformanceCounterPollConfig.java    |   53 -
 .../util/core/BrooklynLanguageExtensions.java   |    2 +-
 .../util/core/BrooklynNetworkUtils.java         |    2 +-
 .../brooklyn/util/core/ResourceUtils.java       |    2 +-
 .../brooklyn/util/core/flags/FlagUtils.java     |    7 +-
 .../brooklyn/util/core/flags/TypeCoercions.java |   16 +-
 .../util/core/http/HttpToolResponse.java        |    2 +-
 .../brooklyn/util/core/internal/Repeater.java   |    2 +-
 .../internal/ssh/sshj/SshjClientConnection.java |    2 +-
 .../util/core/internal/ssh/sshj/SshjTool.java   |    2 +-
 .../util/core/task/BasicExecutionContext.java   |    2 +-
 .../util/core/task/BasicExecutionManager.java   |    2 +-
 .../brooklyn/util/core/task/BasicTask.java      |    2 +-
 .../brooklyn/util/core/task/DynamicTasks.java   |    2 +-
 .../brooklyn/util/core/task/ScheduledTask.java  |    4 +-
 .../brooklyn/util/core/task/ValueResolver.java  |    2 +-
 .../brooklyn/util/core/task/ssh/SshTasks.java   |    5 +-
 .../util/core/text/TemplateProcessor.java       |    8 +-
 ...pache.brooklyn.api.location.LocationResolver |   12 +-
 .../core/BrooklynFeatureEnablementTest.java     |  118 ++
 .../brooklyn/core/BrooklynVersionTest.java      |    2 +-
 .../core/catalog/internal/CatalogDtoTest.java   |    2 +-
 .../core/catalog/internal/CatalogScanTest.java  |    2 +-
 .../core/catalog/internal/CatalogTestUtils.java |    2 +-
 .../catalog/internal/CatalogVersioningTest.java |    2 +-
 .../core/catalog/internal/MyCatalogItems.java   |    4 +-
 ...apListAndOtherStructuredConfigKeyTest.groovy |    6 +-
 .../core/effector/EffectorBasicTest.java        |  183 ++
 .../core/effector/EffectorConcatenateTest.java  |  241 +++
 .../core/effector/EffectorMetadataTest.java     |  166 ++
 .../effector/EffectorSayHiGroovyTest.groovy     |  182 ++
 .../core/effector/EffectorSayHiTest.java        |  173 ++
 .../core/effector/EffectorTaskTest.java         |  437 +++++
 .../core/effector/ssh/SshEffectorTasksTest.java |  265 +++
 .../core/enricher/BasicEnricherTest.java        |  119 ++
 .../core/enricher/EnricherConfigTest.java       |  147 ++
 .../entity/AbstractApplicationLegacyTest.java   |  155 ++
 .../core/entity/AbstractEntityLegacyTest.java   |  131 ++
 .../brooklyn/core/entity/AttributeMapTest.java  |  226 +++
 .../brooklyn/core/entity/AttributeTest.java     |   66 +
 .../entity/ConfigEntityInheritanceTest.java     |  190 ++
 .../core/entity/DependentConfigurationTest.java |  413 +++++
 .../brooklyn/core/entity/DynamicEntityTest.java |   60 +
 .../brooklyn/core/entity/EntitiesTest.java      |  134 ++
 .../brooklyn/core/entity/EntityConfigTest.java  |  178 ++
 .../core/entity/EntityFunctionsTest.java        |   77 +
 .../core/entity/EntityLocationsTest.java        |  126 ++
 .../core/entity/EntityPreManagementTest.java    |  146 ++
 .../core/entity/EntityPredicatesTest.java       |  129 ++
 .../core/entity/EntityRegistrationTest.java     |  102 +
 .../core/entity/EntitySetFromFlagTest.java      |  213 +++
 .../brooklyn/core/entity/EntitySpecTest.java    |  214 +++
 .../core/entity/EntitySubscriptionTest.java     |  242 +++
 .../core/entity/EntitySuppliersTest.java        |   70 +
 .../brooklyn/core/entity/EntityTypeTest.java    |  284 +++
 .../brooklyn/core/entity/OwnedChildrenTest.java |  213 +++
 .../core/entity/PolicyRegistrationTest.java     |  152 ++
 .../entity/RecordingSensorEventListener.java    |  115 ++
 .../brooklyn/core/entity/SanitizerTest.java     |   38 +
 .../drivers/BasicEntityDriverManagerTest.java   |   74 +
 .../drivers/EntityDriverRegistryTest.java       |   59 +
 .../ReflectiveEntityDriverFactoryTest.java      |  169 ++
 .../RegistryEntityDriverFactoryTest.java        |   86 +
 .../downloads/BasicDownloadsRegistryTest.java   |  155 ++
 .../DownloadProducerFromLocalRepoTest.java      |  130 ++
 .../DownloadProducerFromPropertiesTest.java     |  162 ++
 .../downloads/DownloadSubstitutersTest.java     |  131 ++
 .../downloads/FilenameProducersTest.java        |   34 +
 .../drivers/downloads/MyEntityDriver.java       |   44 +
 .../brooklyn/core/entity/hello/HelloEntity.java |   53 +
 .../core/entity/hello/HelloEntityImpl.java      |   31 +
 .../core/entity/hello/LocalEntitiesTest.java    |  282 +++
 .../entity/internal/ConfigMapGroovyTest.groovy  |   61 +
 .../core/entity/internal/ConfigMapTest.java     |  298 +++
 .../EntityConfigMapUsageLegacyTest.java         |  292 +++
 .../internal/EntityConfigMapUsageTest.java      |  318 ++++
 .../lifecycle/LifecycleTransitionTest.java      |   51 +
 .../entity/lifecycle/ServiceStateLogicTest.java |  314 ++++
 .../ApplicationBuilderOverridingTest.java       |  221 +++
 .../proxying/BasicEntityTypeRegistryTest.java   |  135 ++
 .../core/entity/proxying/EntityManagerTest.java |   83 +
 .../core/entity/proxying/EntityProxyTest.java   |  171 ++
 .../proxying/InternalEntityFactoryTest.java     |  109 ++
 .../core/entity/trait/FailingEntity.java        |   84 +
 .../core/entity/trait/FailingEntityImpl.java    |   87 +
 .../core/entity/trait/StartableMethodsTest.java |  127 ++
 .../core/feed/ConfigToAttributesTest.java       |   70 +
 .../apache/brooklyn/core/feed/PollerTest.java   |  108 ++
 .../internal/BrooklynFeatureEnablementTest.java |  117 --
 .../core/location/AbstractLocationTest.java     |  185 ++
 ...regatingMachineProvisioningLocationTest.java |  117 ++
 .../location/LegacyAbstractLocationTest.java    |  151 ++
 .../core/location/LocationConfigTest.java       |  204 ++
 .../core/location/LocationConfigUtilsTest.java  |  156 ++
 .../core/location/LocationExtensionsTest.java   |  187 ++
 .../core/location/LocationManagementTest.java   |   82 +
 .../core/location/LocationPredicatesTest.java   |  102 +
 ...ionPropertiesFromBrooklynPropertiesTest.java |  122 ++
 .../core/location/LocationRegistryTest.java     |  161 ++
 .../core/location/MachineDetailsTest.java       |   83 +
 .../brooklyn/core/location/PortRangesTest.java  |  130 ++
 .../RecordingMachineLocationCustomizer.java     |   71 +
 .../core/location/SimulatedLocation.java        |  141 ++
 .../core/location/TestPortSupplierLocation.java |   90 +
 .../access/BrooklynAccessUtilsTest.java         |  139 ++
 .../PortForwardManagerLocationResolverTest.java |   83 +
 .../access/PortForwardManagerRebindTest.java    |  195 ++
 .../location/access/PortForwardManagerTest.java |  193 ++
 .../location/cloud/CloudMachineNamerTest.java   |  161 ++
 .../location/cloud/CustomMachineNamerTest.java  |   79 +
 .../core/location/geo/HostGeoInfoTest.java      |   52 +
 .../geo/HostGeoLookupIntegrationTest.java       |   87 +
 ...ocalhostExternalIpLoaderIntegrationTest.java |   54 +
 .../AcmeEntitlementManagerTestFixture.java      |    4 +-
 .../core/mgmt/entitlement/EntitlementsTest.java |    4 +-
 .../mgmt/entitlement/EntityEntitlementTest.java |    4 +-
 .../ha/HighAvailabilityManagerInMemoryTest.java |    2 +-
 .../HighAvailabilityManagerSplitBrainTest.java  |    6 +-
 .../ha/HighAvailabilityManagerTestFixture.java  |    2 +-
 .../brooklyn/core/mgmt/ha/HotStandbyTest.java   |    2 +-
 .../core/mgmt/ha/MasterChooserTest.java         |    2 +-
 .../brooklyn/core/mgmt/ha/WarmStandbyTest.java  |    2 +-
 .../core/mgmt/internal/AccessManagerTest.java   |    6 +-
 .../internal/EntityExecutionManagerTest.java    |    8 +-
 .../internal/LocalSubscriptionManagerTest.java  |    2 +-
 .../brooklyn/core/mgmt/osgi/OsgiPathTest.java   |    2 +-
 .../core/mgmt/osgi/OsgiStandaloneTest.java      |    2 +-
 .../mgmt/osgi/OsgiVersionMoreEntityTest.java    |    8 +-
 ...ntoPersisterInMemorySizeIntegrationTest.java |    2 +-
 .../BrooklynMementoPersisterTestFixture.java    |    6 +-
 .../mgmt/persist/FileBasedObjectStoreTest.java  |    2 +-
 .../mgmt/persist/XmlMementoSerializerTest.java  |    6 +-
 .../mgmt/rebind/ActivePartialRebindTest.java    |    6 +-
 .../core/mgmt/rebind/CheckpointEntityTest.java  |    4 +-
 .../mgmt/rebind/RebindCatalogEntityTest.java    |   14 +-
 .../core/mgmt/rebind/RebindCatalogItemTest.java |    4 +-
 ...talogWhenCatalogPersistenceDisabledTest.java |    2 +-
 .../mgmt/rebind/RebindDynamicGroupTest.java     |    2 +-
 .../core/mgmt/rebind/RebindEnricherTest.java    |   14 +-
 .../rebind/RebindEntityDynamicTypeInfoTest.java |    4 +-
 .../core/mgmt/rebind/RebindEntityTest.java      |   22 +-
 .../core/mgmt/rebind/RebindFailuresTest.java    |    8 +-
 .../core/mgmt/rebind/RebindFeedTest.java        |   20 +-
 .../core/mgmt/rebind/RebindGroupTest.java       |    2 +-
 .../core/mgmt/rebind/RebindLocationTest.java    |    2 +-
 .../mgmt/rebind/RebindManagerSorterTest.java    |    2 +-
 .../core/mgmt/rebind/RebindPolicyTest.java      |   10 +-
 .../core/mgmt/rebind/RebindTestFixture.java     |    8 +-
 .../mgmt/rebind/RebindTestFixtureWithApp.java   |    2 +-
 .../core/policy/basic/BasicPolicyTest.java      |    2 +-
 .../core/policy/basic/EnricherTypeTest.java     |    2 +-
 .../core/policy/basic/PolicyConfigTest.java     |    2 +-
 .../policy/basic/PolicySubscriptionTest.java    |    8 +-
 .../core/policy/basic/PolicyTypeTest.java       |    2 +-
 .../core/sensor/HttpRequestSensorTest.java      |   85 +
 .../brooklyn/core/sensor/StaticSensorTest.java  |   55 +
 .../core/server/entity/BrooklynMetricsTest.java |    6 +-
 .../core/test/BrooklynAppLiveTestSupport.java   |    4 +-
 .../core/test/BrooklynAppUnitTestSupport.java   |    6 +-
 .../apache/brooklyn/core/test/HttpService.java  |    2 +-
 .../core/test/entity/NoopStartable.java         |    2 +-
 .../core/test/entity/TestApplication.java       |   10 +-
 .../core/test/entity/TestApplicationImpl.java   |    4 +-
 .../brooklyn/core/test/entity/TestCluster.java  |    2 +-
 .../core/test/entity/TestClusterImpl.java       |    4 +-
 .../brooklyn/core/test/entity/TestEntity.java   |   20 +-
 .../core/test/entity/TestEntityImpl.java        |    6 +-
 .../entity/TestEntityTransientCopyImpl.java     |    2 +-
 .../core/test/location/TestPaasLocation.java    |   32 -
 .../brooklyn/core/test/policy/TestEnricher.java |    2 +-
 .../brooklyn/core/test/policy/TestPolicy.java   |    2 +-
 .../longevity/EntityCleanupLongevityTest.java   |    2 +-
 .../EntityCleanupLongevityTestFixture.java      |    6 +-
 .../test/qa/longevity/EntityCleanupTest.java    |    2 +-
 .../qa/performance/AbstractPerformanceTest.java |    6 +-
 .../qa/performance/EntityPerformanceTest.java   |    2 +-
 .../EntityPersistencePerformanceTest.java       |    2 +-
 .../effector/core/EffectorBasicTest.java        |  183 --
 .../effector/core/EffectorConcatenateTest.java  |  241 ---
 .../effector/core/EffectorMetadataTest.java     |  166 --
 .../core/EffectorSayHiGroovyTest.groovy         |  179 --
 .../effector/core/EffectorSayHiTest.java        |  173 --
 .../effector/core/EffectorTaskTest.java         |  437 -----
 ...stomAggregatingEnricherDeprecatedTest.groovy |  368 ++++
 .../stock/CustomAggregatingEnricherTest.java    |  556 ++++++
 .../brooklyn/enricher/stock/EnrichersTest.java  |  501 +++++
 ...SensorPropagatingEnricherDeprecatedTest.java |  108 ++
 .../stock/SensorPropagatingEnricherTest.java    |  218 +++
 .../TransformingEnricherDeprecatedTest.groovy   |   83 +
 .../stock/TransformingEnricherTest.java         |   71 +
 .../YamlRollingTimeWindowMeanEnricherTest.java  |  179 ++
 .../YamlTimeWeightedDeltaEnricherTest.java      |  107 ++
 .../core/AbstractApplicationLegacyTest.java     |  156 --
 .../entity/core/AbstractEntityLegacyTest.java   |  131 --
 .../brooklyn/entity/core/AttributeMapTest.java  |  226 ---
 .../brooklyn/entity/core/AttributeTest.java     |   66 -
 .../core/ConfigEntityInheritanceTest.java       |  188 --
 .../entity/core/DependentConfigurationTest.java |  413 -----
 .../brooklyn/entity/core/DynamicEntityTest.java |   60 -
 .../brooklyn/entity/core/EntitiesTest.java      |  134 --
 .../brooklyn/entity/core/EntityConfigTest.java  |  178 --
 .../entity/core/EntityFunctionsTest.java        |   77 -
 .../entity/core/EntityLocationsTest.java        |  126 --
 .../entity/core/EntityPreManagementTest.java    |  146 --
 .../entity/core/EntityPredicatesTest.java       |  129 --
 .../entity/core/EntityRegistrationTest.java     |  102 -
 .../entity/core/EntitySetFromFlagTest.java      |  213 ---
 .../brooklyn/entity/core/EntitySpecTest.java    |  214 ---
 .../entity/core/EntitySubscriptionTest.java     |  242 ---
 .../entity/core/EntitySuppliersTest.java        |   70 -
 .../brooklyn/entity/core/EntityTypeTest.java    |  284 ---
 .../brooklyn/entity/core/OwnedChildrenTest.java |  213 ---
 .../entity/core/PolicyRegistrationTest.java     |  152 --
 .../core/RecordingSensorEventListener.java      |  115 --
 .../brooklyn/entity/core/SanitizerTest.java     |   38 -
 .../core/internal/ConfigMapGroovyTest.groovy    |   61 -
 .../entity/core/internal/ConfigMapTest.java     |  298 ---
 .../EntityConfigMapUsageLegacyTest.java         |  292 ---
 .../core/internal/EntityConfigMapUsageTest.java |  318 ----
 .../drivers/BasicEntityDriverManagerTest.java   |   74 -
 .../drivers/EntityDriverRegistryTest.java       |   59 -
 .../ReflectiveEntityDriverFactoryTest.java      |  169 --
 .../RegistryEntityDriverFactoryTest.java        |   86 -
 .../downloads/BasicDownloadsRegistryTest.java   |  155 --
 .../DownloadProducerFromLocalRepoTest.java      |  130 --
 .../DownloadProducerFromPropertiesTest.java     |  162 --
 .../downloads/DownloadSubstitutersTest.java     |  131 --
 .../downloads/FilenameProducersTest.java        |   34 -
 .../drivers/downloads/MyEntityDriver.java       |   44 -
 .../entity/group/DynamicClusterTest.java        |   18 +-
 ...DynamicClusterWithAvailabilityZonesTest.java |   14 +-
 .../entity/group/DynamicFabricTest.java         |   12 +-
 .../brooklyn/entity/group/DynamicGroupTest.java |   10 +-
 .../entity/group/DynamicMultiGroupTest.java     |   10 +-
 .../entity/group/DynamicRegionsFabricTest.java  |    2 +-
 .../entity/group/GroupPickUpEntitiesTest.java   |   10 +-
 .../apache/brooklyn/entity/group/GroupTest.java |    9 +-
 .../group/MembershipTrackingPolicyTest.java     |    6 +-
 .../entity/group/QuarantineGroupTest.java       |    4 +-
 .../BalancingNodePlacementStrategyTest.java     |    2 +-
 .../ProportionalZoneFailureDetectorTest.java    |    2 +-
 .../brooklyn/entity/hello/HelloEntity.java      |   53 -
 .../brooklyn/entity/hello/HelloEntityImpl.java  |   31 -
 .../entity/hello/LocalEntitiesTest.java         |  282 ---
 .../lifecycle/LifecycleTransitionTest.java      |   51 -
 .../entity/lifecycle/ServiceStateLogicTest.java |  314 ----
 .../ApplicationBuilderOverridingTest.java       |  221 ---
 .../proxying/BasicEntityTypeRegistryTest.java   |  135 --
 .../entity/proxying/EntityManagerTest.java      |   83 -
 .../entity/proxying/EntityProxyTest.java        |  171 --
 .../proxying/InternalEntityFactoryTest.java     |  109 --
 .../entity/stock/BasicStartableTest.java        |   15 +-
 .../brooklyn/entity/stock/DataEntityTest.java   |    8 +-
 .../brooklyn/entity/trait/FailingEntity.java    |   84 -
 .../entity/trait/FailingEntityImpl.java         |   87 -
 .../entity/trait/StartableMethodsTest.java      |  127 --
 .../feed/function/FunctionFeedTest.java         |  315 ++++
 .../feed/http/HttpFeedIntegrationTest.java      |  160 ++
 .../apache/brooklyn/feed/http/HttpFeedTest.java |  392 ++++
 .../feed/http/HttpValueFunctionsTest.java       |   94 +
 .../brooklyn/feed/http/JsonFunctionsTest.java   |  130 ++
 .../feed/shell/ShellFeedIntegrationTest.java    |  226 +++
 .../feed/ssh/SshFeedIntegrationTest.java        |  264 +++
 .../WindowsPerformanceCounterFeedLiveTest.java  |  104 ++
 .../WindowsPerformanceCounterFeedTest.java      |  132 ++
 .../access/BrooklynAccessUtilsTest.java         |  137 --
 .../PortForwardManagerLocationResolverTest.java |   82 -
 .../access/PortForwardManagerRebindTest.java    |  194 --
 .../location/access/PortForwardManagerTest.java |  192 --
 .../location/byon/ByonLocationResolverTest.java |   10 +-
 ...stMachineProvisioningLocationRebindTest.java |    6 +-
 ...ixedListMachineProvisioningLocationTest.java |    6 +-
 .../location/byon/HostLocationResolverTest.java |    2 +-
 .../byon/SingleMachineLocationResolverTest.java |    2 +-
 .../location/cloud/CloudMachineNamerTest.java   |  160 --
 .../location/cloud/CustomMachineNamerTest.java  |   78 -
 .../location/core/AbstractLocationTest.java     |  185 --
 ...regatingMachineProvisioningLocationTest.java |  117 --
 .../core/LegacyAbstractLocationTest.java        |  151 --
 .../location/core/LocationConfigTest.java       |  204 --
 .../location/core/LocationConfigUtilsTest.java  |  156 --
 .../location/core/LocationExtensionsTest.java   |  187 --
 .../location/core/LocationManagementTest.java   |   82 -
 .../location/core/LocationPredicatesTest.java   |  102 -
 ...ionPropertiesFromBrooklynPropertiesTest.java |  122 --
 .../location/core/LocationRegistryTest.java     |  161 --
 .../location/core/MachineDetailsTest.java       |   83 -
 .../location/core/MultiLocationRebindTest.java  |  122 --
 .../core/MultiLocationResolverTest.java         |  203 --
 .../location/core/MultiLocationTest.java        |  121 --
 .../location/core/PaasLocationTest.java         |   35 -
 .../brooklyn/location/core/PortRangesTest.java  |  130 --
 .../RecordingMachineLocationCustomizer.java     |   71 -
 .../location/core/SimulatedLocation.java        |  141 --
 .../location/core/TestPortSupplierLocation.java |   90 -
 .../LocalhostLocationResolverTest.java          |  269 ---
 ...ocalhostMachineProvisioningLocationTest.java |  215 ---
 .../LocalhostProvisioningAndAccessTest.java     |   59 -
 .../brooklyn/location/geo/HostGeoInfoTest.java  |   51 -
 .../geo/HostGeoLookupIntegrationTest.java       |   83 -
 ...ocalhostExternalIpLoaderIntegrationTest.java |   53 -
 .../LocalhostLocationResolverTest.java          |  269 +++
 ...ocalhostMachineProvisioningLocationTest.java |  215 +++
 .../LocalhostProvisioningAndAccessTest.java     |   59 +
 .../location/multi/MultiLocationRebindTest.java |  122 ++
 .../multi/MultiLocationResolverTest.java        |  203 ++
 .../location/multi/MultiLocationTest.java       |  121 ++
 .../location/paas/PaasLocationTest.java         |   34 +
 .../location/paas/TestPaasLocation.java         |   32 +
 .../ssh/SshMachineLocationIntegrationTest.java  |    2 +-
 .../SshMachineLocationReuseIntegrationTest.java |    2 +-
 .../location/ssh/SshMachineLocationTest.java    |   26 +-
 .../winrm/WinRmMachineLocationTest.java         |    2 +-
 .../sensor/core/HttpRequestSensorTest.java      |   85 -
 .../brooklyn/sensor/core/StaticSensorTest.java  |   55 -
 .../sensor/enricher/BasicEnricherTest.java      |  119 --
 ...stomAggregatingEnricherDeprecatedTest.groovy |  367 ----
 .../enricher/CustomAggregatingEnricherTest.java |  556 ------
 .../sensor/enricher/EnricherConfigTest.java     |  147 --
 .../brooklyn/sensor/enricher/EnrichersTest.java |  501 -----
 ...SensorPropagatingEnricherDeprecatedTest.java |  108 --
 .../enricher/SensorPropagatingEnricherTest.java |  218 ---
 .../TransformingEnricherDeprecatedTest.groovy   |   82 -
 .../enricher/TransformingEnricherTest.java      |   71 -
 .../YamlRollingTimeWindowMeanEnricherTest.java  |  179 --
 .../YamlTimeWeightedDeltaEnricherTest.java      |  107 --
 .../sensor/feed/ConfigToAttributesTest.java     |   70 -
 .../apache/brooklyn/sensor/feed/PollerTest.java |  108 --
 .../sensor/feed/function/FunctionFeedTest.java  |  315 ----
 .../feed/http/HttpFeedIntegrationTest.java      |  160 --
 .../brooklyn/sensor/feed/http/HttpFeedTest.java |  392 ----
 .../feed/http/HttpValueFunctionsTest.java       |   94 -
 .../sensor/feed/http/JsonFunctionsTest.java     |  130 --
 .../feed/shell/ShellFeedIntegrationTest.java    |  226 ---
 .../sensor/feed/ssh/SshFeedIntegrationTest.java |  264 ---
 .../WindowsPerformanceCounterFeedLiveTest.java  |  104 --
 .../WindowsPerformanceCounterFeedTest.java      |  132 --
 .../util/core/http/HttpToolIntegrationTest.java |    2 +-
 .../util/core/internal/RepeaterTest.groovy      |    4 +-
 .../util/core/internal/TypeCoercionsTest.java   |    2 +-
 .../sshj/SshjToolAsyncStubIntegrationTest.java  |    2 +-
 .../ssh/sshj/SshjToolIntegrationTest.java       |    2 +-
 .../core/ssh/BashCommandsIntegrationTest.java   |    2 +-
 .../brooklyn/util/core/task/TasksTest.java      |    4 +-
 .../util/core/task/ssh/SshTasksTest.java        |    5 +-
 .../util/core/task/system/SystemTasksTest.java  |    2 +-
 .../util/core/text/TemplateProcessorTest.java   |    2 +-
 .../big_examples/global-web-fabric/index.md     |   16 +-
 ...est-app-with-enrichers-slightly-simpler.yaml |    4 +-
 .../brooklyn/demo/GlobalWebFabricExample.java   |   10 +-
 .../brooklyn/demo/KafkaClusterExample.java      |    4 +-
 .../demo/StandaloneQpidBrokerExample.java       |    6 +-
 .../brooklyn/demo/CumulusRDFApplication.java    |   24 +-
 .../demo/HighAvailabilityCassandraCluster.java  |    6 +-
 .../brooklyn/demo/ResilientMongoDbApp.java      |    8 +-
 .../brooklyn/demo/RiakClusterExample.java       |    6 +-
 .../brooklyn/demo/SimpleCassandraCluster.java   |    6 +-
 .../brooklyn/demo/SimpleCouchDBCluster.java     |    2 +-
 .../brooklyn/demo/SimpleMongoDBReplicaSet.java  |    2 +-
 .../brooklyn/demo/SimpleRedisCluster.java       |    2 +-
 .../apache/brooklyn/demo/StormSampleApp.java    |    6 +-
 .../brooklyn/demo/WideAreaCassandraCluster.java |    6 +-
 .../brooklyn/demo/NodeJsTodoApplication.java    |   12 +-
 .../brooklyn/demo/SingleWebServerExample.java   |   10 +-
 .../demo/WebClusterDatabaseExample.java         |   16 +-
 .../demo/WebClusterDatabaseExampleApp.java      |   16 +-
 .../demo/WebClusterDatabaseExampleGroovy.groovy |    8 +-
 .../apache/brooklyn/demo/WebClusterExample.java |    4 +-
 ...lusterDatabaseExampleAppIntegrationTest.java |    6 +-
 .../JcloudsBlobStoreBasedObjectStore.java       |    4 +-
 ...AbstractJcloudsSubnetSshMachineLocation.java |    2 +-
 .../location/jclouds/BrooklynMachinePool.java   |    2 +-
 .../jclouds/ComputeServiceRegistryImpl.java     |    2 +-
 .../jclouds/JcloudsByonLocationResolver.java    |   10 +-
 .../location/jclouds/JcloudsLocation.java       |   22 +-
 .../location/jclouds/JcloudsLocationConfig.java |    8 +-
 .../jclouds/JcloudsLocationResolver.java        |    8 +-
 .../jclouds/JcloudsMachineLocation.java         |    2 +-
 .../location/jclouds/JcloudsMachineNamer.java   |    2 +-
 ...JcloudsPropertiesFromBrooklynProperties.java |    6 +-
 .../jclouds/JcloudsSshMachineLocation.java      |    6 +-
 .../JcloudsLocationSecurityGroupCustomizer.java |    2 +-
 .../JcloudsPortForwarderExtension.java          |    4 +-
 .../zone/AwsAvailabilityZoneExtension.java      |    4 +-
 .../policy/jclouds/os/CreateUserPolicy.java     |   10 +-
 .../mgmt/persist/jclouds/BlobStoreCleaner.java  |    4 +-
 .../persist/jclouds/BlobStoreExpiryTest.java    |    6 +-
 .../mgmt/persist/jclouds/BlobStoreTest.java     |    6 +-
 .../JcloudsBlobStoreBasedObjectStoreTest.java   |    2 +-
 .../jclouds/JcloudsExpect100ContinueTest.java   |    2 +-
 .../JcloudsObjectStoreAccessorWriterTest.java   |    2 +-
 .../jclouds/AbstractJcloudsLiveTest.java        |    2 +-
 .../jclouds/JcloudsAddressesLiveTest.java       |    2 +-
 .../JcloudsByonLocationResolverTest.java        |    2 +-
 .../jclouds/JcloudsLocationMetadataTest.java    |    4 +-
 .../jclouds/JcloudsLocationResolverTest.java    |    4 +-
 .../location/jclouds/JcloudsLocationTest.java   |    8 +-
 .../location/jclouds/LiveTestEntity.java        |    4 +-
 .../jclouds/RebindJcloudsLocationLiveTest.java  |    4 +-
 .../JcloudsPortForwardingStubbedLiveTest.java   |    4 +-
 .../provider/AbstractJcloudsLocationTest.java   |    2 +-
 .../AwsEc2LocationWindowsLiveTest.groovy        |    2 +-
 .../zone/AwsAvailabilityZoneExtensionTest.java  |    2 +-
 parent/pom.xml                                  |    2 +-
 .../policy/autoscaling/AutoScalerPolicy.java    |   12 +-
 .../brooklyn/policy/enricher/DeltaEnricher.java |    2 +-
 .../policy/enricher/HttpLatencyDetector.java    |   14 +-
 .../policy/enricher/RollingMeanEnricher.java    |    2 +-
 .../enricher/RollingTimeWindowMeanEnricher.java |    4 +-
 .../enricher/TimeFractionDeltaEnricher.java     |    2 +-
 .../enricher/TimeWeightedDeltaEnricher.java     |    6 +-
 .../followthesun/DefaultFollowTheSunModel.java  |    2 +-
 .../policy/followthesun/FollowTheSunPolicy.java |    6 +-
 .../policy/followthesun/FollowTheSunPool.java   |    4 +-
 .../followthesun/FollowTheSunPoolImpl.java      |    6 +-
 .../policy/ha/AbstractFailureDetector.java      |    6 +-
 .../policy/ha/ConditionalSuspendPolicy.java     |    4 +-
 .../policy/ha/ConnectionFailureDetector.java    |    2 +-
 .../apache/brooklyn/policy/ha/HASensors.java    |    2 +-
 .../policy/ha/ServiceFailureDetector.java       |   12 +-
 .../brooklyn/policy/ha/ServiceReplacer.java     |   14 +-
 .../brooklyn/policy/ha/ServiceRestarter.java    |   16 +-
 .../policy/ha/SshMachineFailureDetector.java    |    4 +-
 .../loadbalancing/BalanceableContainer.java     |    2 +-
 .../loadbalancing/BalanceableWorkerPool.java    |    4 +-
 .../BalanceableWorkerPoolImpl.java              |    6 +-
 .../loadbalancing/LoadBalancingPolicy.java      |    6 +-
 .../brooklyn/policy/loadbalancing/Movable.java  |    8 +-
 .../autoscaling/AutoScalerPolicyMetricTest.java |    6 +-
 .../autoscaling/AutoScalerPolicyRebindTest.java |    8 +-
 .../AutoScalerPolicyReconfigurationTest.java    |    4 +-
 .../autoscaling/AutoScalerPolicyTest.java       |    6 +-
 .../autoscaling/LocallyResizableEntity.java     |    6 +-
 .../policy/enricher/DeltaEnrichersTests.groovy  |   12 +-
 .../enricher/HttpLatencyDetectorTest.java       |    4 +-
 .../policy/enricher/RebindEnricherTest.java     |    4 +-
 .../enricher/RollingMeanEnricherTest.groovy     |   12 +-
 .../RollingTimeWindowMeanEnricherTest.groovy    |   12 +-
 .../enricher/TimeFractionDeltaEnricherTest.java |   10 +-
 .../AbstractFollowTheSunPolicyTest.java         |    8 +-
 .../followthesun/FollowTheSunModelTest.java     |    2 +-
 .../FollowTheSunPolicySoakTest.java             |    6 +-
 .../followthesun/FollowTheSunPolicyTest.java    |    6 +-
 .../ha/ConnectionFailureDetectorTest.java       |    4 +-
 .../brooklyn/policy/ha/HaPolicyRebindTest.java  |    8 +-
 ...ServiceFailureDetectorStabilizationTest.java |   10 +-
 .../policy/ha/ServiceFailureDetectorTest.java   |   12 +-
 .../brooklyn/policy/ha/ServiceReplacerTest.java |   18 +-
 .../policy/ha/ServiceRestarterTest.java         |   10 +-
 .../AbstractLoadBalancingPolicyTest.java        |    8 +-
 .../BalanceableWorkerPoolTest.java              |    8 +-
 .../ItemsInContainersGroupTest.java             |    6 +-
 .../LoadBalancingPolicyConcurrencyTest.java     |    4 +-
 .../LoadBalancingPolicySoakTest.java            |    4 +-
 .../loadbalancing/LoadBalancingPolicyTest.java  |    4 +-
 .../loadbalancing/MockContainerEntity.java      |    6 +-
 .../loadbalancing/MockContainerEntityImpl.java  |    2 +-
 .../policy/loadbalancing/MockItemEntity.java    |    2 +-
 .../loadbalancing/MockItemEntityImpl.java       |    2 +-
 .../brooklyn/entity/database/Database.groovy    |    2 +-
 .../entity/database/derby/DerbyDatabase.java    |   18 +-
 .../database/derby/DerbyDatabaseDriver.java     |    2 +-
 .../database/derby/DerbyDatabaseSshDriver.java  |    8 +-
 .../entity/database/derby/DerbySchema.java      |   22 +-
 .../postgresql/PostgreSqlNodeSaltImpl.java      |   28 +-
 .../brooklyn/entity/salt/SaltBashCommands.java  |    9 +-
 .../apache/brooklyn/entity/salt/SaltConfig.java |   18 +-
 .../brooklyn/entity/salt/SaltConfigs.java       |   10 +-
 .../entity/salt/SaltLifecycleEffectorTasks.java |   22 +-
 .../brooklyn/entity/salt/SaltStackMaster.java   |   15 +-
 .../entity/salt/SaltStackMasterImpl.java        |    3 +-
 .../entity/salt/SaltStackMasterSshDriver.java   |   10 +-
 .../apache/brooklyn/entity/salt/SaltTasks.java  |   33 +-
 .../postgresql/PostgreSqlSaltLiveTest.java      |   17 +-
 .../brooklyn/entity/salt/SaltConfigsTest.java   |    7 +-
 .../entity/salt/SaltLiveTestSupport.java        |    6 +-
 .../entity/monitoring/zabbix/ZabbixFeed.java    |   20 +-
 .../monitoring/zabbix/ZabbixMonitored.java      |    4 +-
 .../monitoring/zabbix/ZabbixPollConfig.java     |    6 +-
 .../entity/monitoring/zabbix/ZabbixServer.java  |    2 +-
 .../monitoring/zabbix/ZabbixServerImpl.java     |   10 +-
 .../nosql/hazelcast/HazelcastCluster.java       |   14 +-
 .../nosql/hazelcast/HazelcastClusterImpl.java   |   13 +-
 .../entity/nosql/hazelcast/HazelcastNode.java   |   21 +-
 .../nosql/hazelcast/HazelcastNodeImpl.java      |   13 +-
 .../nosql/hazelcast/HazelcastNodeSshDriver.java |   15 +-
 .../nosql/infinispan/Infinispan5Server.java     |   12 +-
 .../nosql/infinispan/Infinispan5SshDriver.java  |   10 +-
 .../hazelcast/HazelcastClusterEc2LiveTest.java  |    7 +-
 .../HazelcastClusterSoftlayerLiveTest.java      |    7 +-
 .../Infinispan5ServerIntegrationTest.groovy     |   12 +-
 .../entity/brooklynnode/BrooklynCluster.java    |    4 +-
 .../brooklynnode/BrooklynClusterImpl.java       |   14 +-
 .../brooklynnode/BrooklynEntityMirror.java      |    2 +-
 .../brooklynnode/BrooklynEntityMirrorImpl.java  |   20 +-
 .../entity/brooklynnode/BrooklynNode.java       |   14 +-
 .../entity/brooklynnode/BrooklynNodeImpl.java   |   32 +-
 .../brooklynnode/BrooklynNodeSshDriver.java     |    6 +-
 .../brooklynnode/RemoteEffectorBuilder.java     |    4 +-
 .../BrooklynClusterUpgradeEffectorBody.java     |   12 +-
 .../BrooklynNodeUpgradeEffectorBody.java        |   12 +-
 .../effector/SelectMasterEffectorBody.java      |    6 +-
 .../SetHighAvailabilityModeEffectorBody.java    |    8 +-
 ...SetHighAvailabilityPriorityEffectorBody.java |    4 +-
 .../brooklyn/entity/chef/ChefAttributeFeed.java |   12 +-
 .../entity/chef/ChefAttributePollConfig.java    |    2 +-
 .../brooklyn/entity/chef/ChefConfigs.java       |    2 +-
 .../entity/chef/ChefLifecycleEffectorTasks.java |    8 +-
 .../brooklyn/entity/chef/ChefSoloDriver.java    |    2 +-
 .../brooklyn/entity/chef/ChefSoloTasks.java     |    2 +-
 .../apache/brooklyn/entity/chef/ChefTasks.java  |    4 +-
 .../entity/chef/KnifeConvergeTaskFactory.java   |    2 +-
 .../brooklyn/entity/java/JavaAppUtils.java      |    8 +-
 .../java/JavaSoftwareProcessSshDriver.java      |   12 +-
 .../entity/java/JmxAttributeSensor.java         |   14 +-
 .../apache/brooklyn/entity/java/JmxSupport.java |   10 +-
 .../brooklyn/entity/java/UsesJavaMXBeans.java   |    4 +-
 .../apache/brooklyn/entity/java/UsesJmx.java    |    8 +-
 .../brooklyn/entity/java/VanillaJavaApp.java    |    2 +-
 .../entity/java/VanillaJavaAppImpl.java         |    2 +-
 .../entity/machine/MachineAttributes.java       |    2 +-
 .../brooklyn/entity/machine/MachineEntity.java  |    6 +-
 .../entity/machine/MachineEntityImpl.java       |   10 +-
 .../entity/machine/MachineInitTasks.java        |    2 +-
 .../entity/machine/pool/ServerPool.java         |   12 +-
 .../entity/machine/pool/ServerPoolImpl.java     |   18 +-
 .../entity/machine/pool/ServerPoolLocation.java |    4 +-
 .../pool/ServerPoolLocationResolver.java        |    8 +-
 .../base/AbstractSoftwareProcessDriver.java     |    8 +-
 .../base/AbstractSoftwareProcessSshDriver.java  |   14 +-
 .../AbstractSoftwareProcessWinRmDriver.java     |    4 +-
 .../software/base/AbstractVanillaProcess.java   |    2 +-
 .../SameServerDriverLifecycleEffectorTasks.java |    6 +-
 .../entity/software/base/SameServerEntity.java  |   10 +-
 .../software/base/SameServerEntityImpl.java     |    8 +-
 .../entity/software/base/SoftwareProcess.java   |   16 +-
 .../software/base/SoftwareProcessDriver.java    |    4 +-
 ...wareProcessDriverLifecycleEffectorTasks.java |   10 +-
 .../software/base/SoftwareProcessImpl.java      |   30 +-
 .../base/VanillaSoftwareProcessSshDriver.java   |    4 +-
 .../software/base/VanillaWindowsProcess.java    |    2 +-
 .../base/VanillaWindowsProcessWinRmDriver.java  |    4 +-
 .../MachineLifecycleEffectorTasks.java          |   32 +-
 .../software/base/lifecycle/ScriptHelper.java   |    2 +-
 .../system_service/EntityLaunchListener.java    |    2 +-
 .../system_service/InitdServiceInstaller.java   |    8 +-
 .../system_service/SystemServiceEnricher.java   |   10 +-
 .../feed/jmx/JmxAttributePollConfig.java        |   74 +
 .../org/apache/brooklyn/feed/jmx/JmxFeed.java   |  423 +++++
 .../org/apache/brooklyn/feed/jmx/JmxHelper.java |  724 ++++++++
 .../feed/jmx/JmxNotificationFilters.java        |   64 +
 .../jmx/JmxNotificationSubscriptionConfig.java  |   95 +
 .../feed/jmx/JmxOperationPollConfig.java        |  121 ++
 .../brooklyn/feed/jmx/JmxValueFunctions.java    |   95 +
 .../sensor/feed/jmx/JmxAttributePollConfig.java |   74 -
 .../brooklyn/sensor/feed/jmx/JmxFeed.java       |  423 -----
 .../brooklyn/sensor/feed/jmx/JmxHelper.java     |  724 --------
 .../sensor/feed/jmx/JmxNotificationFilters.java |   64 -
 .../jmx/JmxNotificationSubscriptionConfig.java  |   95 -
 .../sensor/feed/jmx/JmxOperationPollConfig.java |  121 --
 .../sensor/feed/jmx/JmxValueFunctions.java      |   95 -
 .../brooklyn/sensor/ssh/SshCommandEffector.java |   11 +-
 .../brooklyn/sensor/ssh/SshCommandSensor.java   |   12 +-
 .../brooklyn/sensor/ssh/SshEffectorTasks.java   |  334 ----
 .../winrm/WindowsPerformanceCounterSensors.java |    8 +-
 .../entity/AbstractGoogleComputeLiveTest.java   |    4 +-
 .../entity/AbstractSoftlayerLiveTest.java       |    4 +-
 .../BrooklynNodeIntegrationTest.java            |   12 +-
 .../entity/brooklynnode/BrooklynNodeTest.java   |    8 +-
 .../entity/brooklynnode/MockBrooklynNode.java   |    4 +-
 .../brooklynnode/SameBrooklynNodeImpl.java      |    8 +-
 .../brooklynnode/SelectMasterEffectorTest.java  |   12 +-
 .../brooklyn/entity/chef/ChefConfigsTest.java   |    4 +-
 .../entity/chef/ChefLiveTestSupport.java        |    2 +-
 .../chef/ChefServerTasksIntegrationTest.java    |    4 +-
 .../ChefSoloDriverMySqlEntityLiveTest.java      |    4 +-
 .../mysql/ChefSoloDriverToyMySqlEntity.java     |    6 +-
 .../brooklyn/entity/java/EntityPollingTest.java |    8 +-
 ...SoftwareProcessSshDriverIntegrationTest.java |    4 +-
 .../brooklyn/entity/java/JmxSupportTest.java    |    2 +-
 .../entity/java/VanillaJavaAppRebindTest.java   |    4 +-
 .../entity/java/VanillaJavaAppTest.java         |   10 +-
 .../entity/machine/MachineEntityRebindTest.java |    4 +-
 .../machine/pool/AbstractServerPoolTest.java    |    8 +-
 .../entity/machine/pool/ServerPoolLiveTest.java |    2 +-
 .../pool/ServerPoolLocationResolverTest.java    |    6 +-
 .../machine/pool/ServerPoolRebindTest.java      |    2 +-
 .../entity/machine/pool/ServerPoolTest.java     |    4 +-
 .../software/base/AbstractDockerLiveTest.java   |    4 +-
 ...ctSoftwareProcessRestartIntegrationTest.java |    6 +-
 .../software/base/DoNothingSoftwareProcess.java |    2 +-
 .../base/DoNothingSoftwareProcessDriver.java    |    2 +-
 .../base/DoNothingSoftwareProcessImpl.java      |    2 +-
 .../software/base/SameServerEntityTest.java     |    2 +-
 .../software/base/SoftwareEffectorTest.java     |    8 +-
 .../base/SoftwareProcessEntityLatchTest.java    |    8 +-
 .../base/SoftwareProcessEntityRebindTest.java   |   14 +-
 .../base/SoftwareProcessEntityTest.java         |   28 +-
 ...SoftwareProcessSshDriverIntegrationTest.java |   10 +-
 .../base/SoftwareProcessSubclassTest.java       |    4 +-
 ...ftwareProcessAndChildrenIntegrationTest.java |    4 +-
 .../MachineLifecycleEffectorTasksTest.java      |   14 +-
 .../base/lifecycle/ScriptHelperTest.java        |    8 +-
 .../base/lifecycle/StartStopSshDriverTest.java  |    6 +-
 .../usage/ApplicationUsageTrackingTest.java     |    6 +-
 .../mgmt/usage/LocationUsageTrackingTest.java   |    4 +-
 .../usage/RecordingLegacyUsageListener.java     |    2 +-
 .../core/mgmt/usage/RecordingUsageListener.java |    2 +-
 .../test/core/mgmt/usage/UsageListenerTest.java |    8 +-
 .../base/test/driver/MockSshDriver.java         |    2 +-
 ...rWithAvailabilityZonesMultiLocationTest.java |    6 +-
 .../software/base/test/jmx/JmxService.java      |    4 +-
 .../location/MachineDetailsEc2LiveTest.java     |    6 +-
 .../MachineDetailsGoogleComputeLiveTest.java    |    6 +-
 .../location/WinRmMachineLocationLiveTest.java  |    2 +-
 .../test/mysql/AbstractToyMySqlEntityTest.java  |    8 +-
 .../mysql/DynamicToyMySqlEntityBuilder.java     |    8 +-
 .../PortAttributeSensorAndConfigKeyTest.java    |    4 +-
 .../test/ssh/SshCommandIntegrationTest.java     |   10 +-
 .../SystemServiceEnricherTest.java              |   10 +-
 .../apache/brooklyn/feed/jmx/JmxFeedTest.java   |  422 +++++
 .../apache/brooklyn/feed/jmx/JmxHelperTest.java |  311 ++++
 .../brooklyn/feed/jmx/RebindJmxFeedTest.java    |  148 ++
 .../brooklyn/sensor/feed/jmx/JmxFeedTest.java   |  422 -----
 .../brooklyn/sensor/feed/jmx/JmxHelperTest.java |  311 ----
 .../sensor/feed/jmx/RebindJmxFeedTest.java      |  148 --
 .../sensor/ssh/SshEffectorTasksTest.java        |  264 ---
 .../entity/database/DatastoreMixins.java        |    4 +-
 .../entity/database/crate/CrateNode.java        |   12 +-
 .../entity/database/crate/CrateNodeImpl.java    |   12 +-
 .../database/crate/CrateNodeSshDriver.java      |    4 +-
 .../entity/database/mariadb/MariaDbNode.java    |   12 +-
 .../database/mariadb/MariaDbNodeImpl.java       |   10 +-
 .../database/mariadb/MariaDbSshDriver.java      |    6 +-
 .../entity/database/mysql/MySqlCluster.java     |    4 +-
 .../entity/database/mysql/MySqlClusterImpl.java |   20 +-
 .../entity/database/mysql/MySqlNode.java        |   18 +-
 .../entity/database/mysql/MySqlNodeImpl.java    |   10 +-
 .../entity/database/mysql/MySqlSshDriver.java   |    8 +-
 .../database/postgresql/PostgreSqlNode.java     |    8 +-
 .../PostgreSqlNodeChefImplFromScratch.java      |   14 +-
 .../database/postgresql/PostgreSqlNodeImpl.java |    2 +-
 .../postgresql/PostgreSqlSshDriver.java         |    6 +-
 .../entity/database/rubyrep/RubyRepNode.java    |    8 +-
 .../database/rubyrep/RubyRepNodeImpl.java       |    4 +-
 .../database/rubyrep/RubyRepSshDriver.java      |    6 +-
 .../crate/CrateNodeIntegrationTest.java         |    6 +-
 .../mariadb/MariaDbIntegrationTest.java         |    4 +-
 .../database/postgresql/PostgreSqlChefTest.java |    8 +-
 .../postgresql/PostgreSqlIntegrationTest.java   |    4 +-
 .../postgresql/PostgreSqlRackspaceLiveTest.java |    2 +-
 .../database/rubyrep/RubyRepEc2LiveTest.java    |    2 +-
 .../rubyrep/RubyRepIntegrationTest.java         |    6 +-
 .../rubyrep/RubyRepRackspaceLiveTest.java       |    2 +-
 .../entity/messaging/MessageBroker.java         |    2 +-
 .../apache/brooklyn/entity/messaging/Queue.java |    4 +-
 .../apache/brooklyn/entity/messaging/Topic.java |    2 +-
 .../messaging/activemq/ActiveMQBroker.java      |   10 +-
 .../messaging/activemq/ActiveMQBrokerImpl.java  |    6 +-
 .../activemq/ActiveMQDestinationImpl.java       |    6 +-
 .../messaging/activemq/ActiveMQQueueImpl.java   |    4 +-
 .../messaging/activemq/ActiveMQSshDriver.java   |    2 +-
 .../entity/messaging/amqp/AmqpExchange.java     |    2 +-
 .../entity/messaging/amqp/AmqpServer.java       |    6 +-
 .../entity/messaging/jms/JMSBrokerImpl.java     |    2 +-
 .../messaging/jms/JMSDestinationImpl.java       |    2 +-
 .../kafka/AbstractfKafkaSshDriver.java          |    4 +-
 .../brooklyn/entity/messaging/kafka/Kafka.java  |    4 +-
 .../entity/messaging/kafka/KafkaBroker.java     |    6 +-
 .../entity/messaging/kafka/KafkaBrokerImpl.java |    8 +-
 .../entity/messaging/kafka/KafkaCluster.java    |   10 +-
 .../messaging/kafka/KafkaClusterImpl.java       |   10 +-
 .../entity/messaging/kafka/KafkaZooKeeper.java  |    6 +-
 .../messaging/kafka/KafkaZooKeeperImpl.java     |    2 +-
 .../kafka/KafkaZooKeeperSshDriver.java          |    2 +-
 .../entity/messaging/qpid/QpidBroker.java       |    6 +-
 .../entity/messaging/qpid/QpidBrokerImpl.java   |    8 +-
 .../messaging/qpid/QpidDestinationImpl.java     |    6 +-
 .../entity/messaging/qpid/QpidQueueImpl.java    |    4 +-
 .../entity/messaging/qpid/QpidSshDriver.java    |    2 +-
 .../entity/messaging/rabbit/RabbitBroker.java   |    6 +-
 .../messaging/rabbit/RabbitBrokerImpl.java      |    2 +-
 .../messaging/rabbit/RabbitDestination.java     |    2 +-
 .../entity/messaging/rabbit/RabbitQueue.java    |    6 +-
 .../messaging/rabbit/RabbitSshDriver.java       |    2 +-
 .../brooklyn/entity/messaging/storm/Storm.java  |    6 +-
 .../entity/messaging/storm/StormDeployment.java |    2 +-
 .../messaging/storm/StormDeploymentImpl.java    |    4 +-
 .../entity/messaging/storm/StormImpl.java       |    6 +-
 .../entity/messaging/storm/StormSshDriver.java  |   10 +-
 .../entity/zookeeper/AbstractZooKeeperImpl.java |    6 +-
 .../entity/zookeeper/ZooKeeperEnsemble.java     |    4 +-
 .../entity/zookeeper/ZooKeeperEnsembleImpl.java |    4 +-
 .../entity/zookeeper/ZooKeeperNode.java         |    6 +-
 .../entity/zookeeper/ZooKeeperSshDriver.java    |    2 +-
 .../messaging/activemq/ActiveMQEc2LiveTest.java |    2 +-
 .../activemq/ActiveMQGoogleComputeLiveTest.java |    2 +-
 .../activemq/ActiveMQIntegrationTest.java       |    6 +-
 .../messaging/kafka/KafkaIntegrationTest.java   |    6 +-
 .../entity/messaging/kafka/KafkaLiveTest.java   |    4 +-
 .../entity/messaging/kafka/KafkaSupport.java    |    2 +-
 .../messaging/qpid/QpidIntegrationTest.java     |    8 +-
 .../messaging/rabbit/RabbitIntegrationTest.java |    6 +-
 .../storm/StormAbstractCloudLiveTest.java       |    8 +-
 .../messaging/storm/StormEc2LiveTest.java       |    4 +-
 .../zookeeper/ZooKeeperEc2LiveTest.java         |    4 +-
 .../zookeeper/ZooKeeperEnsembleLiveTest.java    |    8 +-
 .../entity/monitoring/monit/MonitNode.java      |    8 +-
 .../entity/monitoring/monit/MonitNodeImpl.java  |    6 +-
 .../entity/monitoring/monit/MonitSshDriver.java |    2 +-
 .../monitoring/monit/MonitIntegrationTest.java  |    4 +-
 .../entity/network/bind/BindDnsServer.java      |    8 +-
 .../entity/network/bind/BindDnsServerImpl.java  |    6 +-
 .../bind/BindDnsServerIntegrationTest.java      |   12 +-
 .../network/bind/BindDnsServerLiveTest.java     |    4 +-
 .../bind/DoNothingSoftwareProcessDriver.java    |    2 +-
 .../network/bind/PrefixAndIdEnricher.java       |    6 +-
 .../network/bind/TestBindDnsServerImpl.java     |    2 +-
 .../nosql/cassandra/CassandraDatacenter.java    |   10 +-
 .../cassandra/CassandraDatacenterImpl.java      |   16 +-
 .../entity/nosql/cassandra/CassandraFabric.java |    4 +-
 .../nosql/cassandra/CassandraFabricImpl.java    |   10 +-
 .../entity/nosql/cassandra/CassandraNode.java   |   10 +-
 .../nosql/cassandra/CassandraNodeImpl.java      |   26 +-
 .../nosql/cassandra/CassandraNodeSshDriver.java |   14 +-
 .../nosql/couchbase/CouchbaseCluster.java       |    2 +-
 .../nosql/couchbase/CouchbaseClusterImpl.java   |   26 +-
 .../entity/nosql/couchbase/CouchbaseNode.java   |   16 +-
 .../nosql/couchbase/CouchbaseNodeImpl.java      |   16 +-
 .../nosql/couchbase/CouchbaseNodeSshDriver.java |   18 +-
 .../nosql/couchbase/CouchbaseSyncGateway.java   |    6 +-
 .../couchbase/CouchbaseSyncGatewayImpl.java     |    8 +-
 .../CouchbaseSyncGatewaySshDriver.java          |    8 +-
 .../entity/nosql/couchdb/CouchDBCluster.java    |    4 +-
 .../entity/nosql/couchdb/CouchDBNode.java       |    2 +-
 .../entity/nosql/couchdb/CouchDBNodeImpl.java   |    6 +-
 .../nosql/couchdb/CouchDBNodeSshDriver.java     |    2 +-
 .../elasticsearch/ElasticSearchCluster.java     |    2 +-
 .../nosql/elasticsearch/ElasticSearchNode.java  |   10 +-
 .../elasticsearch/ElasticSearchNodeImpl.java    |   10 +-
 .../ElasticSearchNodeSshDriver.java             |    4 +-
 .../nosql/mongodb/AbstractMongoDBServer.java    |    6 +-
 .../nosql/mongodb/AbstractMongoDBSshDriver.java |    4 +-
 .../entity/nosql/mongodb/MongoDBClient.java     |    6 +-
 .../entity/nosql/mongodb/MongoDBClientImpl.java |    2 +-
 .../nosql/mongodb/MongoDBClientSshDriver.java   |    6 +-
 .../nosql/mongodb/MongoDBClientSupport.java     |    3 +-
 .../entity/nosql/mongodb/MongoDBReplicaSet.java |    2 +-
 .../nosql/mongodb/MongoDBReplicaSetImpl.java    |    8 +-
 .../entity/nosql/mongodb/MongoDBServer.java     |    4 +-
 .../entity/nosql/mongodb/MongoDBServerImpl.java |    6 +-
 .../entity/nosql/mongodb/ReplicaSetConfig.java  |    3 +-
 .../sharding/CoLocatedMongoDBRouter.java        |    2 +-
 .../sharding/CoLocatedMongoDBRouterImpl.java    |    8 +-
 .../sharding/MongoDBConfigServerCluster.java    |    2 +-
 .../nosql/mongodb/sharding/MongoDBRouter.java   |    2 +-
 .../mongodb/sharding/MongoDBRouterCluster.java  |    2 +-
 .../sharding/MongoDBRouterClusterImpl.java      |    4 +-
 .../mongodb/sharding/MongoDBRouterImpl.java     |    4 +-
 .../sharding/MongoDBShardClusterImpl.java       |    2 +-
 .../sharding/MongoDBShardedDeployment.java      |    4 +-
 .../sharding/MongoDBShardedDeploymentImpl.java  |   18 +-
 .../entity/nosql/redis/RedisCluster.java        |    2 +-
 .../entity/nosql/redis/RedisClusterImpl.java    |   14 +-
 .../entity/nosql/redis/RedisShardImpl.java      |    2 +-
 .../brooklyn/entity/nosql/redis/RedisStore.java |    6 +-
 .../entity/nosql/redis/RedisStoreImpl.java      |    8 +-
 .../entity/nosql/redis/RedisStoreSshDriver.java |    2 +-
 .../brooklyn/entity/nosql/riak/RiakCluster.java |    4 +-
 .../entity/nosql/riak/RiakClusterImpl.java      |   20 +-
 .../brooklyn/entity/nosql/riak/RiakNode.java    |   14 +-
 .../entity/nosql/riak/RiakNodeImpl.java         |   16 +-
 .../entity/nosql/riak/RiakNodeSshDriver.java    |    6 +-
 .../brooklyn/entity/nosql/solr/SolrServer.java  |    8 +-
 .../entity/nosql/solr/SolrServerImpl.java       |   10 +-
 .../entity/nosql/solr/SolrServerSshDriver.java  |    2 +-
 .../entity/nosql/cassandra/AstyanaxSupport.java |    2 +-
 .../CassandraDatacenterIntegrationTest.java     |    4 +-
 .../cassandra/CassandraDatacenterLiveTest.java  |    6 +-
 ...assandraDatacenterRebindIntegrationTest.java |    2 +-
 .../cassandra/CassandraDatacenterTest.java      |    4 +-
 .../nosql/cassandra/CassandraFabricTest.java    |   14 +-
 .../cassandra/CassandraNodeIntegrationTest.java |    6 +-
 .../nosql/couchbase/CouchbaseOfflineTest.java   |    6 +-
 .../CouchbaseSyncGatewayEc2LiveTest.java        |    2 +-
 .../nosql/couchdb/AbstractCouchDBNodeTest.java  |    6 +-
 .../nosql/couchdb/CouchDBClusterLiveTest.java   |    6 +-
 .../nosql/couchdb/CouchDBNodeEc2LiveTest.java   |    2 +-
 .../couchdb/CouchDBNodeIntegrationTest.java     |    2 +-
 .../nosql/couchdb/CouchDBNodeLiveTest.java      |    2 +-
 .../entity/nosql/couchdb/JcouchdbSupport.java   |    2 +-
 .../ElasticSearchClusterIntegrationTest.java    |    6 +-
 .../ElasticSearchNodeIntegrationTest.java       |   10 +-
 .../nosql/mongodb/MongoDBIntegrationTest.java   |    6 +-
 .../mongodb/MongoDBReplicaSetEc2LiveTest.java   |    2 +-
 .../MongoDBReplicaSetIntegrationTest.java       |    2 +-
 .../entity/nosql/mongodb/MongoDBTestHelper.java |    3 +-
 .../MongoDBConfigServerIntegrationTest.java     |    6 +-
 .../MongoDBShardedDeploymentEc2LiveTest.java    |    2 +-
 ...MongoDBShardedDeploymentIntegrationTest.java |    2 +-
 .../redis/RedisClusterIntegrationTest.java      |    6 +-
 .../nosql/redis/RedisIntegrationTest.java       |    6 +-
 .../nosql/riak/RiakClusterEc2LiveTest.java      |    2 +-
 .../nosql/riak/RiakNodeIntegrationTest.java     |    4 +-
 .../entity/nosql/solr/SolrJSupport.java         |    2 +-
 .../nosql/solr/SolrServerEc2LiveTest.java       |    2 +-
 .../nosql/solr/SolrServerIntegrationTest.java   |    4 +-
 .../entity/nosql/solr/SolrServerLiveTest.java   |    2 +-
 .../entity/osgi/karaf/KarafContainer.java       |   12 +-
 .../entity/osgi/karaf/KarafContainerImpl.java   |   14 +-
 .../entity/osgi/karaf/KarafSshDriver.java       |    2 +-
 .../entity/osgi/karaf/KarafContainerTest.java   |    8 +-
 .../entity/dns/AbstractGeoDnsService.java       |   10 +-
 .../entity/dns/AbstractGeoDnsServiceImpl.java   |   12 +-
 .../dns/geoscaling/GeoscalingDnsService.java    |    4 +-
 .../geoscaling/GeoscalingDnsServiceImpl.java    |    6 +-
 .../geoscaling/GeoscalingScriptGenerator.java   |    2 +-
 .../entity/proxy/AbstractController.java        |    2 +-
 .../entity/proxy/AbstractControllerImpl.java    |   16 +-
 .../AbstractNonProvisionedControllerImpl.java   |    6 +-
 .../brooklyn/entity/proxy/LoadBalancer.java     |   14 +-
 .../entity/proxy/nginx/NginxController.java     |   10 +-
 .../entity/proxy/nginx/NginxControllerImpl.java |   18 +-
 .../entity/proxy/nginx/NginxSshDriver.java      |    8 +-
 .../brooklyn/entity/proxy/nginx/UrlMapping.java |    6 +-
 .../entity/proxy/nginx/UrlMappingImpl.java      |   10 +-
 .../webapp/ControlledDynamicWebAppCluster.java  |   16 +-
 .../ControlledDynamicWebAppClusterImpl.java     |   20 +-
 .../entity/webapp/DynamicWebAppCluster.java     |    2 +-
 .../entity/webapp/DynamicWebAppClusterImpl.java |   10 +-
 .../entity/webapp/DynamicWebAppFabric.java      |    2 +-
 .../entity/webapp/DynamicWebAppFabricImpl.java  |    2 +-
 .../entity/webapp/ElasticJavaWebAppService.java |    8 +-
 .../entity/webapp/JavaWebAppService.java        |    8 +-
 .../webapp/JavaWebAppSoftwareProcessImpl.java   |    4 +-
 .../entity/webapp/JavaWebAppSshDriver.java      |    2 +-
 .../entity/webapp/WebAppServiceConstants.java   |    8 +-
 .../entity/webapp/WebAppServiceMethods.java     |    4 +-
 .../entity/webapp/WebAppServiceMetrics.java     |    8 +-
 .../entity/webapp/jboss/JBoss6Server.java       |    2 +-
 .../entity/webapp/jboss/JBoss6ServerImpl.java   |    8 +-
 .../entity/webapp/jboss/JBoss6SshDriver.java    |    4 +-
 .../entity/webapp/jboss/JBoss7Server.java       |    8 +-
 .../entity/webapp/jboss/JBoss7ServerImpl.java   |   12 +-
 .../entity/webapp/jboss/JBoss7SshDriver.java    |    2 +-
 .../entity/webapp/jetty/Jetty6Server.java       |    4 +-
 .../entity/webapp/jetty/Jetty6ServerImpl.java   |    8 +-
 .../entity/webapp/jetty/Jetty6SshDriver.java    |    2 +-
 .../webapp/nodejs/NodeJsWebAppService.java      |    4 +-
 .../webapp/nodejs/NodeJsWebAppServiceImpl.java  |   12 +-
 .../webapp/nodejs/NodeJsWebAppSshDriver.java    |    2 +-
 .../entity/webapp/tomcat/Tomcat8Server.java     |    2 +-
 .../entity/webapp/tomcat/TomcatServer.java      |    8 +-
 .../entity/webapp/tomcat/TomcatServerImpl.java  |    4 +-
 .../entity/webapp/tomcat/TomcatSshDriver.java   |    2 +-
 .../entity/dns/AbstractGeoDnsServiceTest.java   |   20 +-
 .../geoscaling/GeoscalingIntegrationTest.java   |   14 +-
 .../GeoscalingScriptGeneratorTest.java          |    2 +-
 .../entity/proxy/AbstractControllerTest.java    |   10 +-
 .../brooklyn/entity/proxy/StubAppServer.java    |    8 +-
 .../brooklyn/entity/proxy/UrlMappingTest.java   |   12 +-
 .../nginx/NginxClusterIntegrationTest.java      |    8 +-
 .../nginx/NginxHttpsSslIntegrationTest.java     |    8 +-
 .../proxy/nginx/NginxIntegrationTest.java       |    4 +-
 .../proxy/nginx/NginxLightIntegrationTest.java  |    6 +-
 .../proxy/nginx/NginxRebindIntegrationTest.java |    6 +-
 .../nginx/NginxRebindWithHaIntegrationTest.java |   12 +-
 .../nginx/NginxUrlMappingIntegrationTest.java   |    8 +-
 .../proxy/nginx/NginxWebClusterEc2LiveTest.java |    8 +-
 .../AbstractWebAppFixtureIntegrationTest.java   |   12 +-
 ...lledDynamicWebAppClusterIntegrationTest.java |    8 +-
 .../ControlledDynamicWebAppClusterTest.java     |    8 +-
 .../entity/webapp/DynamicWebAppClusterTest.java |   10 +-
 .../entity/webapp/DynamicWebAppFabricTest.java  |   10 +-
 .../webapp/ElasticCustomLocationTest.java       |   10 +-
 ...ElasticJavaWebAppServiceIntegrationTest.java |    4 +-
 .../webapp/TomcatAutoScalerPolicyTest.java      |    2 +-
 .../webapp/WebAppConcurrentDeployTest.java      |    6 +-
 .../webapp/WebAppLiveIntegrationTest.groovy     |    8 +-
 ...namicWebAppClusterRebindIntegrationTest.java |    8 +-
 ...namicWebAppClusterRebindIntegrationTest.java |    6 +-
 .../jboss/JBoss6ServerAwsEc2LiveTest.java       |    2 +-
 ...Boss6ServerNonInheritingIntegrationTest.java |    2 +-
 .../jboss/JBoss7ServerAwsEc2LiveTest.java       |    2 +-
 .../jboss/JBoss7ServerDockerLiveTest.java       |    2 +-
 ...Boss7ServerNonInheritingIntegrationTest.java |    4 +-
 .../JBoss7ServerRebindingIntegrationTest.java   |    2 +-
 ...ultiVersionWebAppFixtureIntegrationTest.java |    2 +-
 .../Jboss7ServerGoogleComputeLiveTest.java      |    2 +-
 .../JettyWebAppFixtureIntegrationTest.java      |    2 +-
 .../NodeJsWebAppFixtureIntegrationTest.java     |    7 +-
 .../NodeJsWebAppSimpleIntegrationTest.java      |    2 +-
 .../webapp/tomcat/Tomcat8ServerEc2LiveTest.java |    2 +-
 .../tomcat/Tomcat8ServerSoftlayerLiveTest.java  |    2 +-
 ...mcat8ServerWebAppFixtureIntegrationTest.java |    4 +-
 .../webapp/tomcat/TomcatServerEc2LiveTest.java  |    2 +-
 .../tomcat/TomcatServerSoftlayerLiveTest.java   |    2 +-
 ...omcatServerWebAppFixtureIntegrationTest.java |    4 +-
 .../test/entity/TestJavaWebAppEntity.java       |    8 +-
 .../app/ClusterWebServerDatabaseSample.java     |   16 +-
 .../sample/app/SingleWebServerSample.java       |    6 +-
 .../app/SampleLocalhostIntegrationTest.java     |    4 +-
 .../brooklyn/sample/app/SampleUnitTest.java     |    4 +-
 .../camp/brooklyn/YamlLauncherAbstract.java     |    2 +-
 .../api/AssemblyTemplateSpecInstantiator.java   |    2 +-
 .../BrooklynAssemblyTemplateInstantiator.java   |    4 +-
 .../BrooklynComponentTemplateResolver.java      |    4 +-
 .../spi/creation/BrooklynEntityMatcher.java     |    2 +-
 .../creation/BrooklynYamlTypeInstantiator.java  |    2 +-
 .../brooklyn/spi/creation/CampCatalogUtils.java |    2 +-
 .../spi/creation/CampToSpecTransformer.java     |    2 +-
 .../spi/dsl/BrooklynDslDeferredSupplier.java    |    6 +-
 .../spi/dsl/methods/BrooklynDslCommon.java      |    4 +-
 .../brooklyn/spi/dsl/methods/DslComponent.java  |   10 +-
 .../camp/brooklyn/AbstractYamlRebindTest.java   |    4 +-
 .../camp/brooklyn/AbstractYamlTest.java         |    2 +-
 .../BrooklynYamlTypeInstantiatorTest.java       |    2 +-
 .../camp/brooklyn/ByonLocationsYamlTest.java    |   10 +-
 .../camp/brooklyn/DslAndRebindYamlTest.java     |    8 +-
 .../brooklyn/EmptySoftwareProcessYamlTest.java  |    2 +-
 .../EnrichersSlightlySimplerYamlTest.java       |    8 +-
 .../camp/brooklyn/EnrichersYamlTest.java        |    8 +-
 .../camp/brooklyn/EntitiesYamlTest.java         |   16 +-
 ...aWebAppWithDslYamlRebindIntegrationTest.java |    2 +-
 .../brooklyn/JavaWebAppsIntegrationTest.java    |    6 +-
 .../camp/brooklyn/JavaWebAppsMatchingTest.java  |    2 +-
 .../camp/brooklyn/LocationsYamlTest.java        |    2 +-
 .../camp/brooklyn/MapReferenceYamlTest.java     |    2 +-
 .../brooklyn/camp/brooklyn/ObjectsYamlTest.java |    2 +-
 .../camp/brooklyn/PoliciesYamlTest.java         |    4 +-
 .../camp/brooklyn/ReferencedYamlTest.java       |    2 +-
 .../brooklyn/ReferencingYamlTestEntityImpl.java |    2 +-
 .../brooklyn/ReloadBrooklynPropertiesTest.java  |    4 +-
 .../camp/brooklyn/TestEntityWithInitConfig.java |    6 +-
 .../brooklyn/TestEntityWithInitConfigImpl.java  |    2 +-
 .../camp/brooklyn/TestReferencingEnricher.java  |    2 +-
 .../camp/brooklyn/TestReferencingPolicy.java    |    2 +-
 .../TestSensorAndEffectorInitializer.java       |   10 +-
 .../brooklyn/VanillaBashNetcatYamlTest.java     |   12 +-
 .../brooklyn/camp/brooklyn/WrapAppTest.java     |    2 +-
 .../catalog/AbstractCatalogXmlTest.java         |    2 +-
 .../CatalogOsgiVersionMoreEntityTest.java       |    2 +-
 .../brooklyn/catalog/CatalogYamlCombiTest.java  |    2 +-
 .../brooklyn/catalog/CatalogYamlEntityTest.java |    2 +-
 .../catalog/CatalogYamlLocationTest.java        |    2 +-
 .../brooklyn/catalog/CatalogYamlPolicyTest.java |    2 +-
 .../brooklyn/catalog/CatalogYamlRebindTest.java |    6 +-
 .../catalog/CatalogYamlTemplateTest.java        |    2 +-
 .../brooklyn/test/lite/CampYamlLiteTest.java    |   10 +-
 .../test/lite/TestAppAssemblyInstantiator.java  |    2 +-
 ...est-app-with-enrichers-slightly-simpler.yaml |   16 +-
 .../test-webapp-with-averaging-enricher.yaml    |    4 +-
 .../org/apache/brooklyn/cli/CloudExplorer.java  |    4 +-
 .../main/java/org/apache/brooklyn/cli/Main.java |   12 +-
 .../apache/brooklyn/cli/lister/ClassFinder.java |    8 +-
 .../brooklyn/cli/lister/ItemDescriptors.java    |    2 +-
 .../java/org/apache/brooklyn/cli/CliTest.java   |   14 +-
 .../src/test/resources/ExampleAppInFile.groovy  |    2 +-
 .../brooklyn/cli/BaseCliIntegrationTest.java    |    3 +-
 usage/downstream-parent/pom.xml                 |    4 +-
 .../BrooklynJavascriptGuiLauncherTest.java      |    2 +-
 .../brooklyn/launcher/BrooklynLauncher.java     |   10 +-
 .../brooklyn/launcher/BrooklynWebServer.java    |    2 +-
 .../launcher/config/BrooklynGlobalConfig.java   |    4 +-
 .../entity/basic/VanillaSoftwareYamlTest.java   |    2 +-
 .../BrooklynEntityMirrorIntegrationTest.java    |    6 +-
 .../brooklynnode/BrooklynNodeRestTest.java      |    8 +-
 .../BrooklynLauncherRebindTestFixture.java      |    4 +-
 .../brooklyn/launcher/BrooklynLauncherTest.java |    2 +-
 .../launcher/BrooklynWebServerTest.java         |    2 +-
 .../brooklyn/launcher/WebAppRunnerTest.java     |    4 +-
 .../blueprints/AbstractBlueprintTest.java       |    6 +-
 .../qa/load/SimulatedJBoss7ServerImpl.java      |   16 +-
 .../qa/load/SimulatedMySqlNodeImpl.java         |    6 +-
 .../qa/load/SimulatedNginxControllerImpl.java   |   10 +-
 .../brooklyn/qa/load/SimulatedTheeTierApp.java  |   18 +-
 .../SoftlayerObtainPrivateLiveTest.java         |    8 +-
 .../org/apache/brooklyn/qa/load/LoadTest.java   |    6 +-
 .../webcluster/SinusoidalLoadGenerator.java     |    4 +-
 .../qa/longevity/webcluster/WebClusterApp.java  |   10 +-
 .../ApplicationResourceIntegrationTest.java     |    6 +-
 .../rest/client/BrooklynApiRestClientTest.java  |    6 +-
 .../resources/AbstractBrooklynRestResource.java |    2 +-
 .../rest/resources/ApplicationResource.java     |   10 +-
 .../rest/resources/EffectorResource.java        |    2 +-
 .../rest/resources/EntityConfigResource.java    |    6 +-
 .../brooklyn/rest/resources/EntityResource.java |    2 +-
 .../rest/resources/LocationResource.java        |    2 +-
 .../rest/resources/PolicyConfigResource.java    |    2 +-
 .../brooklyn/rest/resources/PolicyResource.java |    4 +-
 .../brooklyn/rest/resources/SensorResource.java |    6 +-
 .../brooklyn/rest/resources/ServerResource.java |   10 +-
 .../brooklyn/rest/resources/UsageResource.java  |    2 +-
 .../rest/transform/ApplicationTransformer.java  |    6 +-
 .../rest/transform/CatalogTransformer.java      |    2 +-
 .../rest/transform/EffectorTransformer.java     |    2 +-
 .../rest/transform/EntityTransformer.java       |    2 +-
 .../rest/transform/LocationTransformer.java     |    6 +-
 .../rest/transform/PolicyTransformer.java       |    4 +-
 .../rest/util/BrooklynRestResourceUtils.java    |   18 +-
 .../brooklyn/rest/util/EntityLocationUtils.java |    2 +-
 .../BrooklynRestApiLauncherTestFixture.java     |    2 +-
 .../brooklyn/rest/HaMasterCheckFilterTest.java  |    2 +-
 .../brooklyn/rest/domain/ApplicationTest.java   |    2 +-
 .../brooklyn/rest/domain/SensorSummaryTest.java |    4 +-
 .../ApplicationResourceIntegrationTest.java     |    2 +-
 .../rest/resources/ApplicationResourceTest.java |   20 +-
 .../rest/resources/CatalogResourceTest.java     |    2 +-
 .../rest/resources/DescendantsTest.java         |    4 +-
 .../resources/EntityConfigResourceTest.java     |    4 +-
 .../rest/resources/EntityResourceTest.java      |    4 +-
 .../rest/resources/LocationResourceTest.java    |    2 +-
 .../rest/resources/ScriptResourceTest.java      |    2 +-
 .../SensorResourceIntegrationTest.java          |    4 +-
 .../rest/resources/SensorResourceTest.java      |    6 +-
 .../rest/resources/ServerShutdownTest.java      |   10 +-
 .../rest/resources/UsageResourceTest.java       |    2 +-
 .../brooklynnode/DeployBlueprintTest.java       |    4 +-
 .../rest/testing/BrooklynRestApiTest.java       |    4 +-
 .../rest/testing/BrooklynRestResourceTest.java  |    2 +-
 .../rest/testing/mocks/CapitalizePolicy.java    |    4 +-
 .../testing/mocks/NameMatcherGroupImpl.java     |    2 +-
 .../rest/testing/mocks/RestMockApp.java         |    2 +-
 .../rest/testing/mocks/RestMockAppBuilder.java  |    4 +-
 .../testing/mocks/RestMockSimpleEntity.java     |   10 +-
 .../testing/mocks/RestMockSimplePolicy.java     |    2 +-
 .../util/BrooklynRestResourceUtilsTest.java     |    8 +-
 .../rest/util/EntityLocationUtilsTest.java      |    8 +-
 .../json/BrooklynJacksonSerializerTest.java     |    4 +-
 .../apache/brooklyn/test/EntityTestUtils.java   |    2 +-
 .../brooklyn/util/GroovyJavaMethods.groovy      |  146 --
 .../util/groovy/GroovyJavaMethods.groovy        |  146 ++
 .../brooklyn/util/groovy/JavadocDummy.java      |   30 +
 .../brooklyn/util/groovy/LanguageUtils.groovy   |  383 ++++
 .../brooklyn/util/groovy/TimeExtras.groovy      |   83 +
 .../brooklyn/util/internal/JavadocDummy.java    |   30 -
 .../brooklyn/util/internal/LanguageUtils.groovy |  383 ----
 .../brooklyn/util/internal/TimeExtras.groovy    |   83 -
 .../util/groovy/LanguageUtilsTest.groovy        |  152 ++
 .../brooklyn/util/groovy/PojoTestingFields.java |   28 +
 .../brooklyn/util/groovy/TimeExtrasTest.groovy  |   49 +
 .../util/internal/LanguageUtilsTest.groovy      |  154 --
 .../util/internal/PojoTestingFields.java        |   28 -
 .../util/internal/TimeExtrasTest.groovy         |   49 -
 .../test/osgi/entities/SimpleApplication.java   |    2 +-
 .../osgi/entities/SimpleApplicationImpl.java    |    4 +-
 .../test/osgi/entities/SimpleEntityImpl.java    |    2 +-
 .../test/osgi/entities/SimpleLocation.java      |    2 +-
 .../test/osgi/entities/SimplePolicy.java        |    2 +-
 .../test/osgi/entities/more/MoreEntity.java     |    2 +-
 .../test/osgi/entities/more/MoreEntityImpl.java |    4 +-
 .../test/osgi/entities/more/MoreLocation.java   |    2 +-
 .../test/osgi/entities/more/MorePolicy.java     |    2 +-
 .../test/osgi/entities/more/MoreTemplate.java   |    2 +-
 .../test/osgi/entities/more/MoreEntity.java     |    2 +-
 .../test/osgi/entities/more/MoreEntityImpl.java |    4 +-
 .../test/osgi/entities/more/MoreEntity.java     |    2 +-
 .../test/osgi/entities/more/MoreEntityImpl.java |    4 +-
 .../test/osgi/entities/more/MoreLocation.java   |    2 +-
 .../test/osgi/entities/more/MorePolicy.java     |    2 +-
 .../test/osgi/entities/more/MoreTemplate.java   |    2 +-
 .../brooklyn/test/BrooklynLeakListener.java     |   89 -
 .../brooklyn/test/LoggingVerboseReporter.java   |   36 -
 .../test/PlatformTestSelectorListener.java      |   57 -
 .../apache/brooklyn/test/StatusListener.java    |  100 -
 .../test/TestResourceUnavailableException.java  |  140 --
 .../apache/brooklyn/test/VerboseReporter.java   |  343 ----
 .../test/support/BrooklynLeakListener.java      |   89 +
 .../test/support/LoggingVerboseReporter.java    |   36 +
 .../support/PlatformTestSelectorListener.java   |   57 +
 .../brooklyn/test/support/StatusListener.java   |  100 +
 .../TestResourceUnavailableException.java       |  140 ++
 .../brooklyn/test/support/VerboseReporter.java  |  343 ++++
 1547 files changed, 54899 insertions(+), 54913 deletions(-)
----------------------------------------------------------------------




[19/36] incubator-brooklyn git commit: Rename o.a.b.sensor.feed to o.a.b.feed and o.a.b.core.feed

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxFeed.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxFeed.java b/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxFeed.java
deleted file mode 100644
index 3b6324c..0000000
--- a/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxFeed.java
+++ /dev/null
@@ -1,423 +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.feed.jmx;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.TimeUnit;
-
-import javax.management.Notification;
-import javax.management.NotificationFilter;
-import javax.management.NotificationListener;
-import javax.management.ObjectName;
-
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
-import org.apache.brooklyn.sensor.feed.AbstractFeed;
-import org.apache.brooklyn.sensor.feed.AttributePollHandler;
-import org.apache.brooklyn.sensor.feed.DelegatingPollHandler;
-import org.apache.brooklyn.sensor.feed.PollHandler;
-import org.apache.brooklyn.sensor.feed.Poller;
-import org.apache.brooklyn.util.time.Duration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.SetMultimap;
-import com.google.common.collect.Sets;
-import com.google.common.reflect.TypeToken;
-
-
-/**
- * Provides a feed of attribute values, by polling or subscribing over jmx.
- * 
- * Example usage (e.g. in an entity that extends {@link SoftwareProcessImpl}):
- * <pre>
- * {@code
- * private JmxFeed feed;
- * 
- * //@Override
- * protected void connectSensors() {
- *   super.connectSensors();
- *   
- *   feed = JmxFeed.builder()
- *       .entity(this)
- *       .period(500, TimeUnit.MILLISECONDS)
- *       .pollAttribute(new JmxAttributePollConfig<Integer>(ERROR_COUNT)
- *           .objectName(requestProcessorMbeanName)
- *           .attributeName("errorCount"))
- *       .pollAttribute(new JmxAttributePollConfig<Boolean>(SERVICE_UP)
- *           .objectName(serverMbeanName)
- *           .attributeName("Started")
- *           .onError(Functions.constant(false)))
- *       .build();
- * }
- * 
- * {@literal @}Override
- * protected void disconnectSensors() {
- *   super.disconnectSensors();
- *   if (feed != null) feed.stop();
- * }
- * }
- * </pre>
- * 
- * @author aled
- */
-public class JmxFeed extends AbstractFeed {
-
-    public static final Logger log = LoggerFactory.getLogger(JmxFeed.class);
-
-    public static final long JMX_CONNECTION_TIMEOUT_MS = 120*1000;
-
-    public static final ConfigKey<JmxHelper> HELPER = ConfigKeys.newConfigKey(JmxHelper.class, "helper");
-    public static final ConfigKey<Boolean> OWN_HELPER = ConfigKeys.newBooleanConfigKey("ownHelper");
-    public static final ConfigKey<String> JMX_URI = ConfigKeys.newStringConfigKey("jmxUri");
-    public static final ConfigKey<Long> JMX_CONNECTION_TIMEOUT = ConfigKeys.newLongConfigKey("jmxConnectionTimeout");
-    
-    @SuppressWarnings("serial")
-    public static final ConfigKey<SetMultimap<String, JmxAttributePollConfig<?>>> ATTRIBUTE_POLLS = ConfigKeys.newConfigKey(
-            new TypeToken<SetMultimap<String, JmxAttributePollConfig<?>>>() {},
-            "attributePolls");
-
-    @SuppressWarnings("serial")
-    public static final ConfigKey<SetMultimap<List<?>, JmxOperationPollConfig<?>>> OPERATION_POLLS = ConfigKeys.newConfigKey(
-            new TypeToken<SetMultimap<List<?>, JmxOperationPollConfig<?>>>() {},
-            "operationPolls");
-
-    @SuppressWarnings("serial")
-    public static final ConfigKey<SetMultimap<NotificationFilter, JmxNotificationSubscriptionConfig<?>>> NOTIFICATION_SUBSCRIPTIONS = ConfigKeys.newConfigKey(
-            new TypeToken<SetMultimap<NotificationFilter, JmxNotificationSubscriptionConfig<?>>>() {},
-            "notificationPolls");
-
-    public static Builder builder() {
-        return new Builder();
-    }
-    
-    public static class Builder {
-        private EntityLocal entity;
-        private JmxHelper helper;
-        private long jmxConnectionTimeout = JMX_CONNECTION_TIMEOUT_MS;
-        private long period = 500;
-        private TimeUnit periodUnits = TimeUnit.MILLISECONDS;
-        private List<JmxAttributePollConfig<?>> attributePolls = Lists.newArrayList();
-        private List<JmxOperationPollConfig<?>> operationPolls = Lists.newArrayList();
-        private List<JmxNotificationSubscriptionConfig<?>> notificationSubscriptions = Lists.newArrayList();
-        private String uniqueTag;
-        private volatile boolean built;
-        
-        public Builder entity(EntityLocal val) {
-            this.entity = val;
-            return this;
-        }
-        public Builder helper(JmxHelper val) {
-            this.helper = val;
-            return this;
-        }
-        public Builder period(Duration duration) {
-            return period(duration.toMilliseconds(), TimeUnit.MILLISECONDS);
-        }
-        public Builder period(long millis) {
-            return period(millis, TimeUnit.MILLISECONDS);
-        }
-        public Builder period(long val, TimeUnit units) {
-            this.period = val;
-            this.periodUnits = units;
-            return this;
-        }
-        public Builder pollAttribute(JmxAttributePollConfig<?> config) {
-            attributePolls.add(config);
-            return this;
-        }
-        public Builder pollOperation(JmxOperationPollConfig<?> config) {
-            operationPolls.add(config);
-            return this;
-        }
-        public Builder subscribeToNotification(JmxNotificationSubscriptionConfig<?> config) {
-            notificationSubscriptions.add(config);
-            return this;
-        }
-        public Builder uniqueTag(String uniqueTag) {
-            this.uniqueTag = uniqueTag;
-            return this;
-        }
-        public JmxFeed build() {
-            built = true;
-            JmxFeed result = new JmxFeed(this);
-            result.setEntity(checkNotNull(entity, "entity"));
-            result.start();
-            return result;
-        }
-        @Override
-        protected void finalize() {
-            if (!built) log.warn("JmxFeed.Builder created, but build() never called");
-        }
-    }
-
-    private final SetMultimap<ObjectName, NotificationListener> notificationListeners = HashMultimap.create();
-
-    /**
-     * For rebind; do not call directly; use builder
-     */
-    public JmxFeed() {
-    }
-
-    protected JmxFeed(Builder builder) {
-        super();
-        if (builder.helper != null) {
-            JmxHelper helper = builder.helper;
-            setConfig(HELPER, helper);
-            setConfig(OWN_HELPER, false);
-            setConfig(JMX_URI, helper.getUrl());
-        }
-        setConfig(JMX_CONNECTION_TIMEOUT, builder.jmxConnectionTimeout);
-        
-        SetMultimap<String, JmxAttributePollConfig<?>> attributePolls = HashMultimap.<String,JmxAttributePollConfig<?>>create();
-        for (JmxAttributePollConfig<?> config : builder.attributePolls) {
-            if (!config.isEnabled()) continue;
-            @SuppressWarnings({ "rawtypes", "unchecked" })
-            JmxAttributePollConfig<?> configCopy = new JmxAttributePollConfig(config);
-            if (configCopy.getPeriod() < 0) configCopy.period(builder.period, builder.periodUnits);
-            attributePolls.put(configCopy.getObjectName().getCanonicalName() + configCopy.getAttributeName(), configCopy);
-        }
-        setConfig(ATTRIBUTE_POLLS, attributePolls);
-        
-        SetMultimap<List<?>, JmxOperationPollConfig<?>> operationPolls = HashMultimap.<List<?>,JmxOperationPollConfig<?>>create();
-        for (JmxOperationPollConfig<?> config : builder.operationPolls) {
-            if (!config.isEnabled()) continue;
-            @SuppressWarnings({ "rawtypes", "unchecked" })
-            JmxOperationPollConfig<?> configCopy = new JmxOperationPollConfig(config);
-            if (configCopy.getPeriod() < 0) configCopy.period(builder.period, builder.periodUnits);
-            operationPolls.put(configCopy.buildOperationIdentity(), configCopy);
-        }
-        setConfig(OPERATION_POLLS, operationPolls);
-        
-        SetMultimap<NotificationFilter, JmxNotificationSubscriptionConfig<?>> notificationSubscriptions = HashMultimap.create();
-        for (JmxNotificationSubscriptionConfig<?> config : builder.notificationSubscriptions) {
-            if (!config.isEnabled()) continue;
-            notificationSubscriptions.put(config.getNotificationFilter(), config);
-        }
-        setConfig(NOTIFICATION_SUBSCRIPTIONS, notificationSubscriptions);
-        initUniqueTag(builder.uniqueTag, attributePolls, operationPolls, notificationSubscriptions);
-    }
-
-    @Override
-    public void setEntity(EntityLocal entity) {
-        if (getConfig(HELPER) == null) {
-            JmxHelper helper = new JmxHelper(entity);
-            setConfig(HELPER, helper);
-            setConfig(OWN_HELPER, true);
-            setConfig(JMX_URI, helper.getUrl());
-        }
-        super.setEntity(entity);
-    }
-    
-    public String getJmxUri() {
-        return getConfig(JMX_URI);
-    }
-    
-    protected JmxHelper getHelper() {
-        return getConfig(HELPER);
-    }
-    
-    @SuppressWarnings("unchecked")
-    protected Poller<Object> getPoller() {
-        return (Poller<Object>) super.getPoller();
-    }
-    
-    @Override
-    protected boolean isConnected() {
-        return super.isConnected() && getHelper().isConnected();
-    }
-    
-    @Override
-    protected void preStart() {
-        /*
-         * All actions on the JmxHelper are done async (through the poller's threading) so we don't 
-         * block on start/rebind if the entity is unreachable 
-         * (without this we get a 120s pause in JmxHelper.connect restarting)
-         */
-        final SetMultimap<NotificationFilter, JmxNotificationSubscriptionConfig<?>> notificationSubscriptions = getConfig(NOTIFICATION_SUBSCRIPTIONS);
-        final SetMultimap<List<?>, JmxOperationPollConfig<?>> operationPolls = getConfig(OPERATION_POLLS);
-        final SetMultimap<String, JmxAttributePollConfig<?>> attributePolls = getConfig(ATTRIBUTE_POLLS);
-        
-        getPoller().submit(new Callable<Void>() {
-               public Void call() {
-                   getHelper().connect(getConfig(JMX_CONNECTION_TIMEOUT));
-                   return null;
-               }
-               @Override public String toString() { return "Connect JMX "+getHelper().getUrl(); }
-           });
-        
-        for (final NotificationFilter filter : notificationSubscriptions.keySet()) {
-            getPoller().submit(new Callable<Void>() {
-                public Void call() {
-                    // TODO Could config.getObjectName have wildcards? Is this code safe?
-                    Set<JmxNotificationSubscriptionConfig<?>> configs = notificationSubscriptions.get(filter);
-                    NotificationListener listener = registerNotificationListener(configs);
-                    ObjectName objectName = Iterables.get(configs, 0).getObjectName();
-                    notificationListeners.put(objectName, listener);
-                    return null;
-                }
-                @Override public String toString() { return "Register JMX notifications: "+notificationSubscriptions.get(filter); }
-            });
-        }
-        
-        // Setup polling of sensors
-        for (final String jmxAttributeName : attributePolls.keys()) {
-            registerAttributePoller(attributePolls.get(jmxAttributeName));
-        }
-        
-        // Setup polling of operations
-        for (final List<?> operationIdentifier : operationPolls.keys()) {
-            registerOperationPoller(operationPolls.get(operationIdentifier));
-        }
-    }
-    
-    @Override
-    protected void preStop() {
-        super.preStop();
-
-        for (Map.Entry<ObjectName, NotificationListener> entry : notificationListeners.entries()) {
-            unregisterNotificationListener(entry.getKey(), entry.getValue());
-        }
-        notificationListeners.clear();
-    }
-    
-    @Override
-    protected void postStop() {
-        super.postStop();
-        JmxHelper helper = getHelper();
-        Boolean ownHelper = getConfig(OWN_HELPER);
-        if (helper != null && ownHelper) helper.terminate();
-    }
-    
-    /**
-     * Registers to poll a jmx-operation for an ObjectName, where all the given configs are for the same ObjectName + operation + parameters.
-     */
-    private void registerOperationPoller(Set<JmxOperationPollConfig<?>> configs) {
-        Set<AttributePollHandler<? super Object>> handlers = Sets.newLinkedHashSet();
-        long minPeriod = Integer.MAX_VALUE;
-        
-        final ObjectName objectName = Iterables.get(configs, 0).getObjectName();
-        final String operationName = Iterables.get(configs, 0).getOperationName();
-        final List<String> signature = Iterables.get(configs, 0).getSignature();
-        final List<?> params = Iterables.get(configs, 0).getParams();
-        
-        for (JmxOperationPollConfig<?> config : configs) {
-            handlers.add(new AttributePollHandler<Object>(config, getEntity(), this));
-            if (config.getPeriod() > 0) minPeriod = Math.min(minPeriod, config.getPeriod());
-        }
-        
-        getPoller().scheduleAtFixedRate(
-                new Callable<Object>() {
-                    public Object call() throws Exception {
-                        if (log.isDebugEnabled()) log.debug("jmx operation polling for {} sensors at {} -> {}", new Object[] {getEntity(), getJmxUri(), operationName});
-                        if (signature.size() == params.size()) {
-                            return getHelper().operation(objectName, operationName, signature, params);
-                        } else {
-                            return getHelper().operation(objectName, operationName, params.toArray());
-                        }
-                    }
-                }, 
-                new DelegatingPollHandler<Object>(handlers), minPeriod);
-    }
-
-    /**
-     * Registers to poll a jmx-attribute for an ObjectName, where all the given configs are for that same ObjectName + attribute.
-     */
-    private void registerAttributePoller(Set<JmxAttributePollConfig<?>> configs) {
-        Set<AttributePollHandler<? super Object>> handlers = Sets.newLinkedHashSet();
-        long minPeriod = Integer.MAX_VALUE;
-        
-        final ObjectName objectName = Iterables.get(configs, 0).getObjectName();
-        final String jmxAttributeName = Iterables.get(configs, 0).getAttributeName();
-        
-        for (JmxAttributePollConfig<?> config : configs) {
-            handlers.add(new AttributePollHandler<Object>(config, getEntity(), this));
-            if (config.getPeriod() > 0) minPeriod = Math.min(minPeriod, config.getPeriod());
-        }
-        
-        // TODO Not good calling this holding the synchronization lock
-        getPoller().scheduleAtFixedRate(
-                new Callable<Object>() {
-                    public Object call() throws Exception {
-                        if (log.isTraceEnabled()) log.trace("jmx attribute polling for {} sensors at {} -> {}", new Object[] {getEntity(), getJmxUri(), jmxAttributeName});
-                        return getHelper().getAttribute(objectName, jmxAttributeName);
-                    }
-                }, 
-                new DelegatingPollHandler<Object>(handlers), minPeriod);
-    }
-
-    /**
-     * Registers to subscribe to notifications for an ObjectName, where all the given configs are for that same ObjectName + filter.
-     */
-    private NotificationListener registerNotificationListener(Set<JmxNotificationSubscriptionConfig<?>> configs) {
-        final List<AttributePollHandler<? super javax.management.Notification>> handlers = Lists.newArrayList();
-
-        final ObjectName objectName = Iterables.get(configs, 0).getObjectName();
-        final NotificationFilter filter = Iterables.get(configs, 0).getNotificationFilter();
-
-        for (final JmxNotificationSubscriptionConfig<?> config : configs) {
-            AttributePollHandler<javax.management.Notification> handler = new AttributePollHandler<javax.management.Notification>(config, getEntity(), this) {
-                @Override protected Object transformValueOnSuccess(javax.management.Notification val) {
-                    if (config.getOnNotification() != null) {
-                        return config.getOnNotification().apply(val);
-                    } else {
-                        Object result = super.transformValueOnSuccess(val);
-                        if (result instanceof javax.management.Notification)
-                            return ((javax.management.Notification)result).getUserData();
-                        return result;
-                    }
-                }
-            };
-            handlers.add(handler);
-        }
-        final PollHandler<javax.management.Notification> compoundHandler = new DelegatingPollHandler<javax.management.Notification>(handlers);
-        
-        NotificationListener listener = new NotificationListener() {
-            @Override public void handleNotification(Notification notification, Object handback) {
-                compoundHandler.onSuccess(notification);
-            }
-        };
-        getHelper().addNotificationListener(objectName, listener, filter);
-        
-        return listener;
-    }
-    
-    private void unregisterNotificationListener(ObjectName objectName, NotificationListener listener) {
-        try {
-            getHelper().removeNotificationListener(objectName, listener);
-        } catch (RuntimeException e) {
-            log.warn("Failed to unregister listener: "+objectName+", "+listener+"; continuing...", e);
-        }
-    }
-    
-    @Override
-    public String toString() {
-        return "JmxFeed["+(getManagementContext()!=null&&getManagementContext().isRunning()?getJmxUri():"mgmt-not-running")+"]";
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxHelper.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxHelper.java b/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxHelper.java
deleted file mode 100644
index 16e4826..0000000
--- a/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxHelper.java
+++ /dev/null
@@ -1,724 +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.feed.jmx;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.apache.brooklyn.util.JavaGroovyEquivalents.groovyTruth;
-import groovy.time.TimeDuration;
-
-import java.io.IOException;
-import java.security.KeyStore;
-import java.security.PrivateKey;
-import java.security.cert.Certificate;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.WeakHashMap;
-import java.util.concurrent.Callable;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-
-import javax.management.AttributeNotFoundException;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.InvalidAttributeValueException;
-import javax.management.JMX;
-import javax.management.ListenerNotFoundException;
-import javax.management.MBeanServerConnection;
-import javax.management.MalformedObjectNameException;
-import javax.management.NotCompliantMBeanException;
-import javax.management.NotificationFilter;
-import javax.management.NotificationListener;
-import javax.management.ObjectInstance;
-import javax.management.ObjectName;
-import javax.management.openmbean.CompositeData;
-import javax.management.openmbean.TabularData;
-import javax.management.remote.JMXConnector;
-import javax.management.remote.JMXConnectorFactory;
-import javax.management.remote.JMXServiceURL;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManager;
-
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.entity.java.JmxSupport;
-import org.apache.brooklyn.entity.java.UsesJmx;
-import org.apache.brooklyn.util.core.crypto.SecureKeys;
-import org.apache.brooklyn.util.crypto.SslTrustUtils;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.exceptions.RuntimeInterruptedException;
-import org.apache.brooklyn.util.jmx.jmxmp.JmxmpAgent;
-import org.apache.brooklyn.util.repeat.Repeater;
-import org.apache.brooklyn.util.time.Duration;
-import org.apache.brooklyn.util.time.Time;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Preconditions;
-import com.google.common.base.Throwables;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-
-public class JmxHelper {
-
-    private static final Logger LOG = LoggerFactory.getLogger(JmxHelper.class);
-
-    public static final String JMX_URL_FORMAT = "service:jmx:rmi:///jndi/rmi://%s:%d/%s";
-    // first host:port may be ignored, so above is sufficient, but not sure
-    public static final String RMI_JMX_URL_FORMAT = "service:jmx:rmi://%s:%d/jndi/rmi://%s:%d/%s";
-    // jmxmp
-    public static final String JMXMP_URL_FORMAT = "service:jmx:jmxmp://%s:%d";
-    
-    // Tracks the MBeans we have failed to find, with a set keyed off the url
-    private static final Map<String, Set<ObjectName>> notFoundMBeansByUrl = Collections.synchronizedMap(new WeakHashMap<String, Set<ObjectName>>());
-
-    public static final Map<String, String> CLASSES = ImmutableMap.<String,String>builder()
-            .put("Integer", Integer.TYPE.getName())
-            .put("Long", Long.TYPE.getName())
-            .put("Boolean", Boolean.TYPE.getName())
-            .put("Byte", Byte.TYPE.getName())
-            .put("Character", Character.TYPE.getName())
-            .put("Double", Double.TYPE.getName())
-            .put("Float", Float.TYPE.getName())
-            .put("GStringImpl", String.class.getName())
-            .put("LinkedHashMap", Map.class.getName())
-            .put("TreeMap", Map.class.getName())
-            .put("HashMap", Map.class.getName())
-            .put("ConcurrentHashMap", Map.class.getName())
-            .put("TabularDataSupport", TabularData.class.getName())
-            .put("CompositeDataSupport", CompositeData.class.getName())
-            .build();
-
-    /** constructs a JMX URL suitable for connecting to the given entity, being smart about JMX/RMI vs JMXMP */
-    public static String toJmxUrl(EntityLocal entity) {
-        String url = entity.getAttribute(UsesJmx.JMX_URL);
-        if (url != null) {
-            return url;
-        } else {
-            new JmxSupport(entity, null).setJmxUrl();
-            url = entity.getAttribute(UsesJmx.JMX_URL);
-            return Preconditions.checkNotNull(url, "Could not find URL for "+entity);
-        }
-    }
-
-    /** constructs an RMI/JMX URL with the given inputs 
-     * (where the RMI Registry Port should be non-null, and at least one must be non-null) */
-    public static String toRmiJmxUrl(String host, Integer jmxRmiServerPort, Integer rmiRegistryPort, String context) {
-        if (rmiRegistryPort != null && rmiRegistryPort > 0) {
-            if (jmxRmiServerPort!=null && jmxRmiServerPort > 0 && jmxRmiServerPort!=rmiRegistryPort) {
-                // we have an explicit known JMX RMI server port (e.g. because we are using the agent),
-                // distinct from the RMI registry port
-                // (if the ports are the same, it is a short-hand, and don't use this syntax!)
-                return String.format(RMI_JMX_URL_FORMAT, host, jmxRmiServerPort, host, rmiRegistryPort, context);
-            }
-            return String.format(JMX_URL_FORMAT, host, rmiRegistryPort, context);
-        } else if (jmxRmiServerPort!=null && jmxRmiServerPort > 0) {
-            LOG.warn("No RMI registry port set for "+host+"; attempting to use JMX port for RMI lookup");
-            return String.format(JMX_URL_FORMAT, host, jmxRmiServerPort, context);
-        } else {
-            LOG.warn("No RMI/JMX details set for "+host+"; returning null");
-            return null;
-        }
-    }
-
-    /** constructs a JMXMP URL for connecting to the given host and port */
-    public static String toJmxmpUrl(String host, Integer jmxmpPort) {
-        return "service:jmx:jmxmp://"+host+(jmxmpPort!=null ? ":"+jmxmpPort : "");
-    }
-    
-    final EntityLocal entity;
-    final String url;
-    final String user;
-    final String password;
-
-    private volatile transient JMXConnector connector;
-    private volatile transient MBeanServerConnection connection;
-    private transient boolean triedConnecting;
-    private transient boolean failedReconnecting;
-    private transient long failedReconnectingTime;
-    private int minTimeBetweenReconnectAttempts = 1000;
-    private final AtomicBoolean terminated = new AtomicBoolean();
-    
-    // Tracks the MBeans we have failed to find for this JmsHelper's connection URL (so can log just once for each)
-    private final Set<ObjectName> notFoundMBeans;
-
-    public JmxHelper(EntityLocal entity) {
-        this(toJmxUrl(entity), entity, entity.getAttribute(UsesJmx.JMX_USER), entity.getAttribute(UsesJmx.JMX_PASSWORD));
-        
-        if (entity.getAttribute(UsesJmx.JMX_URL) == null) {
-            entity.setAttribute(UsesJmx.JMX_URL, url);
-        }
-    }
-    
-    // TODO split this in to two classes, one for entities, and one entity-neutral
-    // (simplifying set of constructors below)
-    
-    public JmxHelper(String url) {
-        this(url, null, null);
-    }
-
-    public JmxHelper(String url, String user, String password) {
-        this(url, null, user, password);
-    }
-    
-    public JmxHelper(String url, EntityLocal entity, String user, String password) {
-        this.url = url;
-        this.entity = entity;
-        this.user = user;
-        this.password = password;
-
-        synchronized (notFoundMBeansByUrl) {
-            Set<ObjectName> set = notFoundMBeansByUrl.get(url);
-            if (set == null) {
-                set = Collections.synchronizedSet(Collections.newSetFromMap(new WeakHashMap<ObjectName, Boolean>()));
-                notFoundMBeansByUrl.put(url, set);
-            }
-            notFoundMBeans = set;
-        }
-    }
-
-    public void setMinTimeBetweenReconnectAttempts(int val) {
-        minTimeBetweenReconnectAttempts = val;
-    }
-    
-    public String getUrl(){
-        return url;
-    }
-
-    // ============== connection related calls =======================
-
-    //for tesing purposes
-    protected MBeanServerConnection getConnection() {
-        return connection;
-    }
-
-    /**
-     * Checks if the JmxHelper is connected. Returned value could be stale as soon
-     * as it is received.
-     *
-     * This method is thread safe.
-     *
-     * @return true if connected, false otherwise.
-     */
-    public boolean isConnected() {
-        return connection!=null;
-    }
-
-    /**
-     * Reconnects. If it already is connected, it disconnects first.
-     *
-     * @throws IOException
-     */
-    public synchronized void reconnectWithRetryDampened() throws IOException {
-        // If we've already tried reconnecting very recently, don't try again immediately
-        if (failedReconnecting) {
-            long timeSince = (System.currentTimeMillis() - failedReconnectingTime);
-            if (timeSince < minTimeBetweenReconnectAttempts) {
-                String msg = "Not reconnecting to JMX at "+url+" because attempt failed "+Time.makeTimeStringRounded(timeSince)+" ago";
-                throw new IllegalStateException(msg);
-            }
-        }
-        
-        reconnect();
-    }
-    
-    public synchronized void reconnect() throws IOException {
-        disconnect();
-
-        try {
-            connect();
-            failedReconnecting = false;
-        } catch (Exception e) {
-            if (failedReconnecting) {
-                if (LOG.isDebugEnabled()) LOG.debug("unable to re-connect to JMX url (repeated failure): {}: {}", url, e);
-            } else {
-                LOG.debug("unable to re-connect to JMX url {} (rethrowing): {}", url, e);
-                failedReconnecting = true;
-            }
-            failedReconnectingTime = System.currentTimeMillis();
-            throw Throwables.propagate(e);
-        }
-    }
-
-    /** attempts to connect immediately */
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    public synchronized void connect() throws IOException {
-        if (terminated.get()) throw new IllegalStateException("JMX Helper "+this+" already terminated");
-        if (connection != null) return;
-
-        triedConnecting = true;
-        if (connector != null) connector.close();
-        JMXServiceURL serviceUrl = new JMXServiceURL(url);
-        Map env = getConnectionEnvVars();
-        try {
-            connector = JMXConnectorFactory.connect(serviceUrl, env);
-        } catch (NullPointerException npe) {
-            //some software -- eg WSO2 -- will throw an NPE exception if the JMX connection can't be created, instead of an IOException.
-            //this is a break of contract with the JMXConnectorFactory.connect method, so this code verifies if the NPE is
-            //thrown by a known offender (wso2) and if so replaces the bad exception by a new IOException.
-            //ideally WSO2 will fix this bug and we can remove this code.
-            boolean thrownByWso2 = npe.getStackTrace()[0].toString().contains("org.wso2.carbon.core.security.CarbonJMXAuthenticator.authenticate");
-            if (thrownByWso2) {
-                throw new IOException("Failed to connect to url "+url+". NullPointerException is thrown, but replaced by an IOException to fix a WSO2 JMX problem", npe);
-            } else {
-                throw npe;
-            }
-        } catch (IOException e) {
-            Exceptions.propagateIfFatal(e);
-            if (terminated.get()) {
-                throw new IllegalStateException("JMX Helper "+this+" already terminated", e);
-            } else {
-                throw e;
-            }
-        }
-        connection = connector.getMBeanServerConnection();
-        
-        if (terminated.get()) {
-            disconnectNow();
-            throw new IllegalStateException("JMX Helper "+this+" already terminated");
-        }
-    }
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    public Map getConnectionEnvVars() {
-        Map env = new LinkedHashMap();
-        
-        if (groovyTruth(user) && groovyTruth(password)) {
-            String[] creds = new String[] {user, password};
-            env.put(JMXConnector.CREDENTIALS, creds);
-        }
-        
-        if (entity!=null && groovyTruth(entity.getConfig(UsesJmx.JMX_SSL_ENABLED))) {
-            env.put("jmx.remote.profiles", JmxmpAgent.TLS_JMX_REMOTE_PROFILES);
-
-            PrivateKey key = entity.getConfig(UsesJmx.JMX_SSL_ACCESS_KEY);
-            Certificate cert = entity.getConfig(UsesJmx.JMX_SSL_ACCESS_CERT);
-            KeyStore ks = SecureKeys.newKeyStore();
-            try {
-                KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
-                if (key!=null) {
-                    ks.setKeyEntry("brooklyn-jmx-access", key, "".toCharArray(), new Certificate[] { cert });
-                }
-                kmf.init(ks, "".toCharArray());
-
-                TrustManager tms = 
-                        // TODO use root cert for trusting server
-                        //trustStore!=null ? SecureKeys.getTrustManager(trustStore) : 
-                        SslTrustUtils.TRUST_ALL;
-
-                SSLContext ctx = SSLContext.getInstance("TLSv1");
-                ctx.init(kmf.getKeyManagers(), new TrustManager[] { tms }, null);
-                SSLSocketFactory ssf = ctx.getSocketFactory(); 
-                env.put(JmxmpAgent.TLS_SOCKET_FACTORY_PROPERTY, ssf); 
-                
-            } catch (Exception e) {
-                LOG.warn("Error setting key "+key+" for "+entity+": "+e, e);
-            }
-        }
-        
-        return env;
-    }
-
-    /**
-     * Continuously attempts to connect for at least the indicated amount of time; or indefinitely if -1. This method
-     * is useful when you are not sure if the system you are trying to connect to already is up and running.
-     *
-     * This method doesn't throw an Exception, but returns true on success, false otherwise.
-     *
-     * TODO: What happens if already connected?
-     *
-     * @param timeoutMs
-     * @return
-     */
-    public boolean connect(long timeoutMs) {
-        if (LOG.isDebugEnabled()) LOG.debug("Connecting to JMX URL: {} ({})", url, ((timeoutMs == -1) ? "indefinitely" : timeoutMs+"ms timeout"));
-        long startMs = System.currentTimeMillis();
-        long endMs = (timeoutMs == -1) ? Long.MAX_VALUE : (startMs + timeoutMs);
-        long currentTime = startMs;
-        Throwable lastError = null;
-        int attempt = 0;
-        while (currentTime <= endMs) {
-            currentTime = System.currentTimeMillis();
-            if (attempt != 0) sleep(100); //sleep 100 to prevent thrashing and facilitate interruption
-            if (LOG.isTraceEnabled()) LOG.trace("trying connection to {} at time {}", url, currentTime);
-
-            try {
-                connect();
-                return true;
-            } catch (Exception e) {
-                Exceptions.propagateIfFatal(e);
-                if (!terminated.get() && shouldRetryOn(e)) {
-                    if (LOG.isDebugEnabled()) LOG.debug("Attempt {} failed connecting to {} ({})", new Object[] {attempt + 1, url, e.getMessage()});
-                    lastError = e;
-                } else {
-                    throw Exceptions.propagate(e);
-                }
-            }
-            attempt++;
-        }
-        LOG.warn("unable to connect to JMX url: "+url, lastError);
-        return false;
-    }
-
-    private boolean shouldRetryOn(Exception e) {
-        // Expect SecurityException, IOException, etc.
-        // But can also see things like javax.naming.ServiceUnavailableException with WSO2 app-servers.
-        // So let's not try to second guess strange behaviours that future entities will exhibit.
-        //
-        // However, if it was our request that was invalid then not worth retrying.
-        
-        if (e instanceof AttributeNotFoundException) return false;
-        if (e instanceof InstanceAlreadyExistsException) return false;
-        if (e instanceof InstanceNotFoundException) return false;
-        if (e instanceof InvalidAttributeValueException) return false;
-        if (e instanceof ListenerNotFoundException) return false;
-        if (e instanceof MalformedObjectNameException) return false;
-        if (e instanceof NotCompliantMBeanException) return false;
-        if (e instanceof InterruptedException) return false;
-        if (e instanceof RuntimeInterruptedException) return false;
-
-        return true;
-    }
-
-    /**
-     * A thread-safe version of {@link #disconnectNow()}.
-     *
-     * This method is threadsafe.
-     */
-    public synchronized void disconnect() {
-        disconnectNow();
-    }
-    
-    /**
-     * Disconnects, preventing subsequent connections to be made. Method doesn't throw an exception.
-     *
-     * Can safely be called if already disconnected.
-     *
-     * This method is not threadsafe, but will thus not block if 
-     * another thread is taking a long time for connections to timeout.
-     * 
-     * Any concurrent requests will likely get an IOException - see
-     * {@linkplain http://docs.oracle.com/javase/7/docs/api/javax/management/remote/JMXConnector.html#close()}.
-     * 
-     */
-    public void terminate() {
-        terminated.set(true);
-        disconnectNow();
-    }
-    
-    protected void disconnectNow() {
-        triedConnecting = false;
-        if (connector != null) {
-            if (LOG.isDebugEnabled()) LOG.debug("Disconnecting from JMX URL {}", url);
-            try {
-                connector.close();
-            } catch (Exception e) {
-                // close attempts to connect to close cleanly; and if it can't, it throws;
-                // often we disconnect as part of shutdown, even if the other side has already stopped --
-                // so swallow exceptions (no situations known where we need a clean closure on the remote side)
-                if (LOG.isDebugEnabled()) LOG.debug("Caught exception disconnecting from JMX at {} ({})", url, e.getMessage());
-                if (LOG.isTraceEnabled()) LOG.trace("Details for exception disconnecting JMX", e);
-            } finally {
-                connector = null;
-                connection = null;
-            }
-        }
-    }
-
-    /**
-     * Gets a usable MBeanServerConnection.
-     *
-     * Method is threadsafe.
-     *
-     * @returns the MBeanServerConnection
-     * @throws IllegalStateException if not connected.
-     */
-    private synchronized MBeanServerConnection getConnectionOrFail() {
-        if (isConnected())
-            return getConnection();
-
-        if (triedConnecting) {
-            throw new IllegalStateException("Failed to connect to JMX at "+url);
-        } else {
-            String msg = "Not connected (and not attempted to connect) to JMX at "+url+
-                    (failedReconnecting ? (" (last reconnect failure at "+ Time.makeDateString(failedReconnectingTime) + ")") : "");
-            throw new IllegalStateException(msg);
-        }
-    }
-
-    private <T> T invokeWithReconnect(Callable<T> task) {
-        try {
-            return task.call();
-        } catch (Exception e) {
-            if (shouldRetryOn(e)) {
-                try {
-                    reconnectWithRetryDampened();
-                    return task.call();
-                } catch (Exception e2) {
-                    throw Throwables.propagate(e2);
-                }
-            } else {
-                throw Throwables.propagate(e);
-            }
-        }
-    }
-
-    // ====================== query related calls =======================================
-
-    /**
-     * Converts from an object name pattern to a real object name, by querying with findMBean; 
-     * if no matching MBean can be found (or if more than one match found) then returns null.
-     * If the supplied object name is not a pattern then just returns that. If the 
-     */
-    public ObjectName toLiteralObjectName(ObjectName objectName) {
-        if (checkNotNull(objectName, "objectName").isPattern()) {
-            ObjectInstance bean = findMBean(objectName);    
-            return (bean != null) ? bean.getObjectName() : null;
-        } else {
-            return objectName;
-        }
-    }
-    
-    public Set<ObjectInstance> findMBeans(final ObjectName objectName) {
-        return invokeWithReconnect(new Callable<Set<ObjectInstance>>() {
-                public Set<ObjectInstance> call() throws Exception {
-                    return getConnectionOrFail().queryMBeans(objectName, null);
-                }});
-    }
-
-    public ObjectInstance findMBean(ObjectName objectName) {
-        Set<ObjectInstance> beans = findMBeans(objectName);
-        if (beans.size() == 1) {
-            notFoundMBeans.remove(objectName);
-            return Iterables.getOnlyElement(beans);
-        } else {
-            boolean changed = notFoundMBeans.add(objectName);
-
-            if (beans.size() > 1) {
-                if (changed) {
-                    LOG.warn("JMX object name query returned {} values for {} at {}; ignoring all",
-                            new Object[] {beans.size(), objectName.getCanonicalName(), url});
-                } else {
-                    if (LOG.isDebugEnabled()) LOG.debug("JMX object name query returned {} values for {} at {} (repeating); ignoring all", 
-                            new Object[] {beans.size(), objectName.getCanonicalName(), url});
-                }
-            } else {
-                if (changed) {
-                    LOG.warn("JMX object {} not found at {}", objectName.getCanonicalName(), url);
-                } else {
-                    if (LOG.isDebugEnabled()) LOG.debug("JMX object {} not found at {} (repeating)", objectName.getCanonicalName(), url);
-                }
-            }
-            return null;
-        }
-    }
-
-    public Set<ObjectInstance> doesMBeanExistsEventually(final ObjectName objectName, Duration timeout) {
-        return doesMBeanExistsEventually(objectName, timeout.toMilliseconds(), TimeUnit.MILLISECONDS);
-    }
-    public Set<ObjectInstance> doesMBeanExistsEventually(final ObjectName objectName, TimeDuration timeout) {
-        return doesMBeanExistsEventually(objectName, timeout.toMilliseconds(), TimeUnit.MILLISECONDS);
-    }
-    
-    public Set<ObjectInstance> doesMBeanExistsEventually(final ObjectName objectName, long timeoutMillis) {
-        return doesMBeanExistsEventually(objectName, timeoutMillis, TimeUnit.MILLISECONDS);
-    }
-    
-    public Set<ObjectInstance> doesMBeanExistsEventually(String objectName, Duration timeout) {
-        return doesMBeanExistsEventually(createObjectName(objectName), timeout);
-    }
-    public Set<ObjectInstance> doesMBeanExistsEventually(String objectName, TimeDuration timeout) {
-        return doesMBeanExistsEventually(createObjectName(objectName), timeout);
-    }
-    
-    public Set<ObjectInstance> doesMBeanExistsEventually(String objectName, long timeout, TimeUnit timeUnit) {
-        return doesMBeanExistsEventually(createObjectName(objectName), timeout, timeUnit);
-    }
-
-    /** returns set of beans found, with retry, empty set if none after timeout */
-    public Set<ObjectInstance> doesMBeanExistsEventually(final ObjectName objectName, long timeout, TimeUnit timeUnit) {
-        final long timeoutMillis = timeUnit.toMillis(timeout);
-        final AtomicReference<Set<ObjectInstance>> beans = new AtomicReference<Set<ObjectInstance>>(ImmutableSet.<ObjectInstance>of());
-        try {
-            Repeater.create("Wait for "+objectName)
-                    .limitTimeTo(timeout, timeUnit)
-                    .every(500, TimeUnit.MILLISECONDS)
-                    .until(new Callable<Boolean>() {
-                            public Boolean call() {
-                                connect(timeoutMillis);
-                                beans.set(findMBeans(objectName));
-                                return !beans.get().isEmpty();
-                            }})
-                    .rethrowException()
-                    .run();
-            return beans.get();
-        } catch (Exception e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-
-    public void assertMBeanExistsEventually(ObjectName objectName, Duration timeout) {
-        assertMBeanExistsEventually(objectName, timeout.toMilliseconds(), TimeUnit.MILLISECONDS);
-    }
-    public void assertMBeanExistsEventually(ObjectName objectName, TimeDuration timeout) {
-        assertMBeanExistsEventually(objectName, timeout.toMilliseconds(), TimeUnit.MILLISECONDS);
-    }
-    
-    public void assertMBeanExistsEventually(ObjectName objectName, long timeoutMillis) {
-        assertMBeanExistsEventually(objectName, timeoutMillis, TimeUnit.MILLISECONDS);
-    }
-    
-    public void assertMBeanExistsEventually(ObjectName objectName, long timeout, TimeUnit timeUnit) {
-        Set<ObjectInstance> beans = doesMBeanExistsEventually(objectName, timeout, timeUnit);
-        if (beans.size() != 1) {
-            throw new IllegalStateException("MBean "+objectName+" not found within "+timeout+
-                    (beans.size() > 1 ? "; found multiple matches: "+beans : ""));
-        }
-    }
-
-    /**
-     * Returns a specific attribute for a JMX {@link ObjectName}.
-     */
-    public Object getAttribute(ObjectName objectName, final String attribute) {
-        final ObjectName realObjectName = toLiteralObjectName(objectName);
-        
-        if (realObjectName != null) {
-            Object result = invokeWithReconnect(new Callable<Object>() {
-                    public Object call() throws Exception {
-                        return getConnectionOrFail().getAttribute(realObjectName, attribute);
-                    }});
-
-            if (LOG.isTraceEnabled()) LOG.trace("From {}, for jmx attribute {}.{}, got value {}", new Object[] {url, objectName.getCanonicalName(), attribute, result});
-            return result;
-        } else {
-            return null;
-        }
-    }
-
-    public void setAttribute(String objectName, String attribute, Object val) {
-        setAttribute(createObjectName(objectName), attribute, val);
-    }
-
-    public void setAttribute(ObjectName objectName, final String attribute, final Object val) {
-        final ObjectName realObjectName = toLiteralObjectName(objectName);
-        
-        if (realObjectName != null) {
-            invokeWithReconnect(new Callable<Void>() {
-                    public Void call() throws Exception {
-                        getConnectionOrFail().setAttribute(realObjectName, new javax.management.Attribute(attribute, val));
-                        return null;
-                    }});
-            if (LOG.isTraceEnabled()) LOG.trace("From {}, for jmx attribute {}.{}, set value {}", new Object[] {url, objectName.getCanonicalName(), attribute, val});
-        } else {
-            if (LOG.isDebugEnabled()) LOG.debug("From {}, cannot set attribute {}.{}, because mbean not found", new Object[] {url, objectName.getCanonicalName(), attribute});
-        }
-    }
-
-    /** @see #operation(ObjectName, String, Object ...) */
-    public Object operation(String objectName, String method, Object... arguments) {
-        return operation(createObjectName(objectName), method, arguments);
-    }
-
-    /**
-     * Executes an operation on a JMX {@link ObjectName}.
-     */
-    public Object operation(ObjectName objectName, final String method, final Object... arguments) {
-        final ObjectName realObjectName = toLiteralObjectName(objectName);
-        final String[] signature = new String[arguments.length];
-        for (int i = 0; i < arguments.length; i++) {
-            Class<?> clazz = arguments[i].getClass();
-            signature[i] = (CLASSES.containsKey(clazz.getSimpleName()) ? CLASSES.get(clazz.getSimpleName()) : clazz.getName());
-        }
-        
-        Object result = invokeWithReconnect(new Callable<Object>() {
-                public Object call() throws Exception {
-                    return getConnectionOrFail().invoke(realObjectName, method, arguments, signature);
-                }});
-
-        if (LOG.isTraceEnabled()) LOG.trace("From {}, for jmx operation {}.{}({}), got value {}", new Object[] {url, realObjectName.getCanonicalName(), method, Arrays.asList(arguments), 
-                result});
-        return result;
-    }
-
-    public void addNotificationListener(String objectName, NotificationListener listener) {
-        addNotificationListener(createObjectName(objectName), listener, null);
-    }
-    
-    public void addNotificationListener(String objectName, NotificationListener listener, NotificationFilter filter) {
-        addNotificationListener(createObjectName(objectName), listener, filter);
-    }
-
-    public void addNotificationListener(ObjectName objectName, NotificationListener listener) {
-        addNotificationListener(objectName, listener, null);
-    }
-    
-    public void addNotificationListener(final ObjectName objectName, final NotificationListener listener, final NotificationFilter filter) {
-        invokeWithReconnect(new Callable<Void>() {
-                public Void call() throws Exception {
-                    getConnectionOrFail().addNotificationListener(objectName, listener, filter, null);
-                    return null;
-                }});
-    }
-
-    public void removeNotificationListener(String objectName, NotificationListener listener) {
-        removeNotificationListener(createObjectName(objectName), listener);
-    }
-
-    public void removeNotificationListener(final ObjectName objectName, final NotificationListener listener) {
-        removeNotificationListener(objectName, listener, null);
-    }
-    
-    public void removeNotificationListener(final ObjectName objectName, final NotificationListener listener, final NotificationFilter filter) {
-        if (isConnected()) invokeWithReconnect(new Callable<Void>() {
-                public Void call() throws Exception {
-                    getConnectionOrFail().removeNotificationListener(objectName, listener, filter, null);
-                    return null;
-                }});
-    }
-
-    public <M> M getProxyObject(String objectName, Class<M> mbeanInterface) {
-        return getProxyObject(createObjectName(objectName), mbeanInterface);
-    }
-
-    public <M> M getProxyObject(ObjectName objectName, Class<M> mbeanInterface) {
-        MBeanServerConnection connection = getConnectionOrFail();
-        return JMX.newMBeanProxy(connection, objectName, mbeanInterface, false);
-    }
-
-    public static ObjectName createObjectName(String name) {
-        try {
-            return new ObjectName(name);
-        } catch (MalformedObjectNameException e) {
-            throw Throwables.propagate(e);
-        }
-    }
-    
-    private static void sleep(long sleepTimeMillis) {
-        try {
-            Thread.sleep(sleepTimeMillis);
-        } catch (InterruptedException e) {
-            throw new RuntimeInterruptedException(e);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxNotificationFilters.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxNotificationFilters.java b/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxNotificationFilters.java
deleted file mode 100644
index 182866a..0000000
--- a/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxNotificationFilters.java
+++ /dev/null
@@ -1,64 +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.feed.jmx;
-
-import javax.management.Notification;
-import javax.management.NotificationFilter;
-import javax.management.NotificationFilterSupport;
-
-public class JmxNotificationFilters {
-
-    private JmxNotificationFilters() {} // instead use static utility methods
-    
-    /**
-     * Matches the given notification type.
-     * @see {@link NotificationFilterSupport#enableType(String)}
-     */
-    public static NotificationFilter matchesType(String type) {
-        return matchesTypes(type);
-    }
-
-    /**
-     * Matches any of the given notification types.
-     * @see {@link NotificationFilterSupport#enableType(String)}
-     */
-    public static NotificationFilter matchesTypes(String... types) {
-        NotificationFilterSupport result = new NotificationFilterSupport();
-        for (String type : types) {
-            result.enableType(type);
-        }
-        return result;
-    }
-
-    /**
-     * @deprecated since 0.6.0;
-     *             only works if this brooklyn class is on the classpath of the JVM that your 
-     *             subscribing to notifications on (because it tries to push the filter instance
-     *             to that JVM). So of very limited use in real-world java processes to be managed.
-     *             Therefore this will be deleted to avoid people hitting this surprising behaviour.
-     */
-    @SuppressWarnings("serial")
-    public static NotificationFilter matchesTypeRegex(final String typeRegex) {
-        return new NotificationFilter() {
-            @Override public boolean isNotificationEnabled(Notification notif) {
-                return notif.getType().matches(typeRegex);
-            }
-        };
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxNotificationSubscriptionConfig.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxNotificationSubscriptionConfig.java b/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxNotificationSubscriptionConfig.java
deleted file mode 100644
index 2a99c62..0000000
--- a/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxNotificationSubscriptionConfig.java
+++ /dev/null
@@ -1,95 +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.feed.jmx;
-
-import javax.management.MalformedObjectNameException;
-import javax.management.Notification;
-import javax.management.NotificationFilter;
-import javax.management.ObjectName;
-
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.sensor.feed.FeedConfig;
-import org.apache.brooklyn.util.collections.MutableList;
-
-import com.google.common.base.Function;
-import com.google.common.base.Functions;
-
-public class JmxNotificationSubscriptionConfig<T> extends FeedConfig<javax.management.Notification, T, JmxNotificationSubscriptionConfig<T>>{
-
-    private ObjectName objectName;
-    private NotificationFilter notificationFilter;
-    private Function<Notification, T> onNotification;
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    public JmxNotificationSubscriptionConfig(AttributeSensor<T> sensor) {
-        super(sensor);
-        onSuccess((Function)Functions.identity());
-    }
-
-    public JmxNotificationSubscriptionConfig(JmxNotificationSubscriptionConfig<T> other) {
-        super(other);
-        this.objectName = other.objectName;
-        this.notificationFilter = other.notificationFilter;
-        this.onNotification = other.onNotification;
-    }
-
-    public ObjectName getObjectName() {
-        return objectName;
-    }
-
-    public NotificationFilter getNotificationFilter() {
-        return notificationFilter;
-    }
-    
-    public Function<Notification, T> getOnNotification() {
-        return onNotification;
-    }
-    
-    public JmxNotificationSubscriptionConfig<T> objectName(ObjectName val) {
-        this.objectName = val; return this;
-    }
-    
-    public JmxNotificationSubscriptionConfig<T> objectName(String val) {
-        try {
-            return objectName(new ObjectName(val));
-        } catch (MalformedObjectNameException e) {
-            throw new IllegalArgumentException("Invalid object name ("+val+")", e);
-        }
-    }
-    
-    public JmxNotificationSubscriptionConfig<T> notificationFilter(NotificationFilter val) {
-        this.notificationFilter = val; return this;
-    }
-
-    public JmxNotificationSubscriptionConfig<T> onNotification(Function<Notification,T> val) {
-        this.onNotification = val; return this;
-    }
-
-    @Override
-    protected Object toStringPollSource() {
-        return objectName;
-    }
-
-    @Override
-    protected MutableList<Object> equalsFields() {
-        return super.equalsFields()
-            .appendIfNotNull(notificationFilter).appendIfNotNull(onNotification);
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxOperationPollConfig.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxOperationPollConfig.java b/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxOperationPollConfig.java
deleted file mode 100644
index b72a4ee..0000000
--- a/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxOperationPollConfig.java
+++ /dev/null
@@ -1,121 +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.feed.jmx;
-
-import java.util.Collections;
-import java.util.List;
-
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
-
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.sensor.feed.PollConfig;
-
-import com.google.common.base.Function;
-import com.google.common.base.Functions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-
-public class JmxOperationPollConfig<T> extends PollConfig<Object, T, JmxOperationPollConfig<T>>{
-
-    private ObjectName objectName;
-    private String operationName;
-    private List<String> signature = Collections.emptyList();
-    private List<?> params = Collections.emptyList();
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    public JmxOperationPollConfig(AttributeSensor<T> sensor) {
-        super(sensor);
-        onSuccess((Function)Functions.identity());
-    }
-
-    public JmxOperationPollConfig(JmxOperationPollConfig<T> other) {
-        super(other);
-        this.objectName = other.objectName;
-        this.operationName = other.operationName;
-        this.signature = other.signature != null ? ImmutableList.copyOf(other.signature) : null;
-        this.params = other.params != null ? ImmutableList.copyOf(other.params) : null;
-    }
-
-    public ObjectName getObjectName() {
-        return objectName;
-    }
-    
-    public String getOperationName() {
-        return operationName;
-    }
-    
-    public List<String> getSignature() {
-        return signature;
-    }
-    
-    public List<?> getParams() {
-        return params;
-    }
-    
-    public JmxOperationPollConfig<T> objectName(ObjectName val) {
-        this.objectName = val; return this;
-    }
-    
-    public JmxOperationPollConfig<T> objectName(String val) {
-        try {
-            return objectName(new ObjectName(val));
-        } catch (MalformedObjectNameException e) {
-            throw new IllegalArgumentException("Invalid object name ("+val+")", e);
-        }
-    }
-
-    public JmxOperationPollConfig<T> operationName(String val) {
-        this.operationName = val; return this;
-    }
-    
-    public JmxOperationPollConfig<T> operationSignature(List<String> val) {
-        this.signature = val; return this;
-    }
-    
-    public JmxOperationPollConfig<T> operationParams(List<?> val) {
-        this.params = val; return this;
-    }
-
-    public List<?> buildOperationIdentity() {
-        // FIXME Have a build() method for ensuring signature is set, and making class subsequently immutable?
-        return ImmutableList.of(operationName, buildSignature(), params);
-    }
-    
-    private List<String> buildSignature() {
-        if (signature != null && signature.size() == params.size()) {
-            return signature;
-        } else {
-            List<String> derivedSignature = Lists.newLinkedList();
-            for (Object param : params) {
-                Class<?> clazz = (param != null) ? param.getClass() : null;
-                String clazzName = (clazz != null) ? 
-                         (JmxHelper.CLASSES.containsKey(clazz.getSimpleName()) ? 
-                                 JmxHelper.CLASSES.get(clazz.getSimpleName()) : clazz.getName()) : 
-                         Object.class.getName();
-                derivedSignature.add(clazzName);
-            }
-            return derivedSignature;
-        }
-    }
-
-    @Override protected String toStringBaseName() { return "jmx"; }
-    @Override protected String toStringPollSource() { return objectName+":"+operationName+(params!=null ? params : "[]"); }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxValueFunctions.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxValueFunctions.java b/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxValueFunctions.java
deleted file mode 100644
index d0b5e21..0000000
--- a/software/base/src/main/java/org/apache/brooklyn/sensor/feed/jmx/JmxValueFunctions.java
+++ /dev/null
@@ -1,95 +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.feed.jmx;
-
-import java.util.List;
-import java.util.Map;
-
-import javax.management.openmbean.CompositeData;
-import javax.management.openmbean.TabularData;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Function;
-import com.google.common.collect.Maps;
-
-public class JmxValueFunctions {
-
-    private static final Logger log = LoggerFactory.getLogger(JmxValueFunctions.class);
-    
-    /**
-     * @return a closure that converts a TabularDataSupport to a map.
-     */
-    public static Function<TabularData, Map> tabularDataToMap() {
-        return new Function<TabularData, Map>() {
-            @Override public Map apply(TabularData input) {
-                return tabularDataToMap(input);
-            }};
-    }
-
-    public static Function<TabularData, Map> tabularDataToMapOfMaps() {
-        return new Function<TabularData, Map>() {
-            @Override public Map apply(TabularData input) {
-                return tabularDataToMapOfMaps(input);
-            }};
-    }
-
-    public static Function<CompositeData,Map> compositeDataToMap() {
-        return new Function<CompositeData, Map>() {
-            @Override public Map apply(CompositeData input) {
-                return compositeDataToMap(input);
-            }};
-    }
-    
-    public static Map tabularDataToMap(TabularData table) {
-        Map<String, Object> result = Maps.newLinkedHashMap();
-        for (Object entry : table.values()) {
-            CompositeData data = (CompositeData) entry; //.getValue()
-            for (String key : data.getCompositeType().keySet()) {
-                Object old = result.put(key, data.get(key));
-                if (old != null) {
-                    log.warn("tablularDataToMap has overwritten key {}", key);
-                }
-            }
-        }
-        return result;
-    }
-    
-    public static Map<List<?>, Map<String, Object>> tabularDataToMapOfMaps(TabularData table) {
-        Map<List<?>, Map<String, Object>> result = Maps.newLinkedHashMap();
-        for (Object k : table.keySet()) {
-            final Object[] kValues = ((List<?>)k).toArray();
-            CompositeData v = (CompositeData) table.get(kValues);
-            result.put((List<?>)k, compositeDataToMap(v));
-        }
-        return result;
-    }
-    
-    public static Map<String, Object> compositeDataToMap(CompositeData data) {
-        Map<String, Object> result = Maps.newLinkedHashMap();
-        for (String key : data.getCompositeType().keySet()) {
-            Object old = result.put(key, data.get(key));
-            if (old != null) {
-                log.warn("compositeDataToMap has overwritten key {}", key);
-            }
-        }
-        return result;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandSensor.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandSensor.java b/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandSensor.java
index 59dc3c2..31c116f 100644
--- a/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandSensor.java
+++ b/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandSensor.java
@@ -28,9 +28,9 @@ import org.apache.brooklyn.core.effector.AddSensor;
 import org.apache.brooklyn.core.sensor.HttpRequestSensor;
 import org.apache.brooklyn.entity.java.JmxAttributeSensor;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.feed.ssh.SshFeed;
-import org.apache.brooklyn.sensor.feed.ssh.SshPollConfig;
-import org.apache.brooklyn.sensor.feed.ssh.SshValueFunctions;
+import org.apache.brooklyn.feed.ssh.SshFeed;
+import org.apache.brooklyn.feed.ssh.SshPollConfig;
+import org.apache.brooklyn.feed.ssh.SshValueFunctions;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.flags.TypeCoercions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/main/java/org/apache/brooklyn/sensor/winrm/WindowsPerformanceCounterSensors.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/sensor/winrm/WindowsPerformanceCounterSensors.java b/software/base/src/main/java/org/apache/brooklyn/sensor/winrm/WindowsPerformanceCounterSensors.java
index ad02ce9..3e0e4c6 100644
--- a/software/base/src/main/java/org/apache/brooklyn/sensor/winrm/WindowsPerformanceCounterSensors.java
+++ b/software/base/src/main/java/org/apache/brooklyn/sensor/winrm/WindowsPerformanceCounterSensors.java
@@ -27,7 +27,7 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.sensor.Sensors;
-import org.apache.brooklyn.sensor.feed.windows.WindowsPerformanceCounterFeed;
+import org.apache.brooklyn.feed.windows.WindowsPerformanceCounterFeed;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.text.Strings;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeIntegrationTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeIntegrationTest.java
index 0cfa8f4..1c54ba1 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeIntegrationTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeIntegrationTest.java
@@ -52,7 +52,7 @@ import org.apache.brooklyn.entity.brooklynnode.BrooklynNode.StopNodeAndKillAppsE
 import org.apache.brooklyn.entity.software.base.SoftwareProcess.StopSoftwareParameters.StopMode;
 import org.apache.brooklyn.entity.stock.BasicApplication;
 import org.apache.brooklyn.entity.stock.BasicApplicationImpl;
-import org.apache.brooklyn.sensor.feed.http.JsonFunctions;
+import org.apache.brooklyn.feed.http.JsonFunctions;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.test.HttpTestUtils;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeTest.java
index 75ca2ff..6c777cf 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeTest.java
@@ -29,11 +29,11 @@ import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.feed.ConfigToAttributes;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNodeImpl;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNodeSshDriver;
-import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/SameBrooklynNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/SameBrooklynNodeImpl.java b/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/SameBrooklynNodeImpl.java
index e117651..9fd2e5c 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/SameBrooklynNodeImpl.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/SameBrooklynNodeImpl.java
@@ -26,9 +26,9 @@ import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
 import org.apache.brooklyn.entity.brooklynnode.EntityHttpClient;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNodeImpl.DeployBlueprintEffectorBody;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
 
 /** Implementation of BrooklynNode which just presents the node where this is running, for convenience;
  * 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/SelectMasterEffectorTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/SelectMasterEffectorTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/SelectMasterEffectorTest.java
index ff8884b..9669e02 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/SelectMasterEffectorTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/SelectMasterEffectorTest.java
@@ -34,6 +34,9 @@ import org.apache.brooklyn.api.entity.Group;
 import org.apache.brooklyn.api.mgmt.ha.ManagementNodeState;
 import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.feed.AttributePollHandler;
+import org.apache.brooklyn.core.feed.DelegatingPollHandler;
+import org.apache.brooklyn.core.feed.Poller;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynCluster;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynClusterImpl;
@@ -41,9 +44,6 @@ import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynCluster.SelectMasterEffector;
 import org.apache.brooklyn.entity.brooklynnode.CallbackEntityHttpClient.Request;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.sensor.feed.AttributePollHandler;
-import org.apache.brooklyn.sensor.feed.DelegatingPollHandler;
-import org.apache.brooklyn.sensor.feed.Poller;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverToyMySqlEntity.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverToyMySqlEntity.java b/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverToyMySqlEntity.java
index 7d3c895..70b20ad 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverToyMySqlEntity.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverToyMySqlEntity.java
@@ -27,8 +27,8 @@ import org.apache.brooklyn.entity.chef.ChefConfig;
 import org.apache.brooklyn.entity.chef.ChefConfigs;
 import org.apache.brooklyn.entity.chef.ChefSoloDriver;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
-import org.apache.brooklyn.sensor.feed.ssh.SshFeed;
-import org.apache.brooklyn.sensor.feed.ssh.SshPollConfig;
+import org.apache.brooklyn.feed.ssh.SshFeed;
+import org.apache.brooklyn.feed.ssh.SshPollConfig;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/test/java/org/apache/brooklyn/entity/java/EntityPollingTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/java/EntityPollingTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/java/EntityPollingTest.java
index 17b7f15..eae757a 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/java/EntityPollingTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/java/EntityPollingTest.java
@@ -32,8 +32,8 @@ import org.apache.brooklyn.entity.java.VanillaJavaAppSshDriver;
 import org.apache.brooklyn.entity.java.UsesJmx.JmxAgentModes;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.software.base.test.jmx.JmxService;
-import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;
-import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
+import org.apache.brooklyn.feed.jmx.JmxAttributePollConfig;
+import org.apache.brooklyn.feed.jmx.JmxFeed;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.exceptions.Exceptions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/test/java/org/apache/brooklyn/entity/java/VanillaJavaAppTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/java/VanillaJavaAppTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/java/VanillaJavaAppTest.java
index e56243c..20e3e63 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/java/VanillaJavaAppTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/java/VanillaJavaAppTest.java
@@ -51,7 +51,7 @@ import org.apache.brooklyn.entity.java.JavaAppUtils;
 import org.apache.brooklyn.entity.java.UsesJava;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.entity.java.VanillaJavaApp;
-import org.apache.brooklyn.sensor.feed.jmx.JmxHelper;
+import org.apache.brooklyn.feed.jmx.JmxHelper;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.ResourceUtils;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/test/java/org/apache/brooklyn/entity/software/base/lifecycle/ScriptHelperTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/lifecycle/ScriptHelperTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/lifecycle/ScriptHelperTest.java
index 8c4d37a..080b5c0 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/lifecycle/ScriptHelperTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/lifecycle/ScriptHelperTest.java
@@ -31,8 +31,8 @@ import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessEntityTest;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessEntityTest.MyService;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessEntityTest.MyServiceImpl;
-import org.apache.brooklyn.sensor.feed.function.FunctionFeed;
-import org.apache.brooklyn.sensor.feed.function.FunctionPollConfig;
+import org.apache.brooklyn.feed.function.FunctionFeed;
+import org.apache.brooklyn.feed.function.FunctionPollConfig;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.time.Duration;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/jmx/JmxService.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/jmx/JmxService.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/jmx/JmxService.java
index ab88f2c..2e23789 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/jmx/JmxService.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/jmx/JmxService.java
@@ -46,7 +46,7 @@ import mx4j.tools.naming.NamingServiceMBean;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.entity.java.UsesJmx;
-import org.apache.brooklyn.sensor.feed.jmx.JmxHelper;
+import org.apache.brooklyn.feed.jmx.JmxHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 


[10/36] incubator-brooklyn git commit: Rename o.a.b.sensor.core to o.a.b.core.sensor

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBRouterCluster.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBRouterCluster.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBRouterCluster.java
index 9093ac4..a313c1c 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBRouterCluster.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBRouterCluster.java
@@ -22,8 +22,8 @@ import java.util.Collection;
 
 import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.sensor.core.Sensors;
 
 @ImplementedBy(MongoDBRouterClusterImpl.class)
 public interface MongoDBRouterCluster extends DynamicCluster {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBShardedDeployment.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBShardedDeployment.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBShardedDeployment.java
index 2752fbe..d48313c 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBShardedDeployment.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBShardedDeployment.java
@@ -27,9 +27,9 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.nosql.mongodb.MongoDBReplicaSet;
 import org.apache.brooklyn.entity.nosql.mongodb.MongoDBServer;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBShardedDeploymentImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBShardedDeploymentImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBShardedDeploymentImpl.java
index 5ec9723..cbebbec 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBShardedDeploymentImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBShardedDeploymentImpl.java
@@ -18,7 +18,7 @@
  */
 package org.apache.brooklyn.entity.nosql.mongodb.sharding;
 
-import static org.apache.brooklyn.sensor.core.DependentConfiguration.attributeWhenReady;
+import static org.apache.brooklyn.core.sensor.DependentConfiguration.attributeWhenReady;
 
 import java.util.Collection;
 import java.util.List;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisClusterImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisClusterImpl.java
index 4f13e44..838def8 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisClusterImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisClusterImpl.java
@@ -29,8 +29,8 @@ import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ComputeServiceIndicatorsFromChildrenAndMembers;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceProblemsLogic;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.collections.QuorumCheck.QuorumChecks;
 import org.apache.brooklyn.util.exceptions.CompoundRuntimeException;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisStore.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisStore.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisStore.java
index 9f27f5f..6b98b3b 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisStore.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisStore.java
@@ -23,10 +23,10 @@ import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakCluster.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakCluster.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakCluster.java
index 8ba0658..e6de705 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakCluster.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakCluster.java
@@ -28,8 +28,8 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakClusterImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakClusterImpl.java
index df60e48..d3a9b70 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakClusterImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakClusterImpl.java
@@ -38,9 +38,9 @@ import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceNotUpLogic;
 import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.entity.group.AbstractMembershipTrackingPolicy;
 import org.apache.brooklyn.entity.group.DynamicClusterImpl;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.core.task.Tasks;
 import org.apache.brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNode.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNode.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNode.java
index 4b43757..358e8cb 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNode.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNode.java
@@ -30,11 +30,11 @@ import org.apache.brooklyn.core.annotation.EffectorParam;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.java.UsesJava;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.AttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeImpl.java
index 9ddabe4..090f36d 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeImpl.java
@@ -32,9 +32,9 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
 import org.apache.brooklyn.core.location.cloud.CloudLocationConfig;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
 import org.apache.brooklyn.entity.webapp.WebAppServiceMethods;
-import org.apache.brooklyn.sensor.core.AttributeSensorAndConfigKey;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.sensor.feed.http.HttpFeed;
 import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/solr/SolrServer.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/solr/SolrServer.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/solr/SolrServer.java
index 1045762..702d595 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/solr/SolrServer.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/solr/SolrServer.java
@@ -26,12 +26,12 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
 import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.java.UsesJava;
 import org.apache.brooklyn.entity.java.UsesJavaMXBeans;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeIntegrationTest.java b/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeIntegrationTest.java
index ce1553b..831b9a7 100644
--- a/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeIntegrationTest.java
+++ b/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeIntegrationTest.java
@@ -28,9 +28,9 @@ import java.util.Map;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.nosql.cassandra.CassandraNode;
 import org.apache.brooklyn.entity.nosql.cassandra.AstyanaxSupport.AstyanaxSample;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.test.NetworkingTestUtils;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainer.java
----------------------------------------------------------------------
diff --git a/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainer.java b/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainer.java
index 7bb7890..e605c08 100644
--- a/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainer.java
+++ b/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainer.java
@@ -29,12 +29,12 @@ import org.apache.brooklyn.core.annotation.EffectorParam;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.config.MapConfigKey;
 import org.apache.brooklyn.core.effector.MethodEffector;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.java.UsesJava;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/AbstractGeoDnsService.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/AbstractGeoDnsService.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/AbstractGeoDnsService.java
index bfa91a0..2896b48 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/AbstractGeoDnsService.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/AbstractGeoDnsService.java
@@ -29,7 +29,7 @@ import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.location.geo.HostGeoInfo;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
 
 import com.google.common.reflect.TypeToken;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingDnsService.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingDnsService.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingDnsService.java
index 983fda3..f421df7 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingDnsService.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingDnsService.java
@@ -26,9 +26,9 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.BasicConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
 import org.apache.brooklyn.entity.dns.AbstractGeoDnsService;
 import org.apache.brooklyn.entity.webapp.WebAppServiceConstants;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 @ImplementedBy(GeoscalingDnsServiceImpl.class)

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/AbstractController.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/AbstractController.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/AbstractController.java
index 1e8cc84..ec3d7a8 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/AbstractController.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/AbstractController.java
@@ -24,9 +24,9 @@ import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.group.Cluster;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/LoadBalancer.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/LoadBalancer.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/LoadBalancer.java
index e4d6262..2a81d0d 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/LoadBalancer.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/LoadBalancer.java
@@ -30,10 +30,10 @@ import org.apache.brooklyn.core.config.BasicConfigKey;
 import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.webapp.WebAppService;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxController.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxController.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxController.java
index 35e28ba..649973d 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxController.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxController.java
@@ -29,11 +29,11 @@ import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.annotation.EffectorParam;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.effector.MethodEffector;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.proxy.AbstractController;
 import org.apache.brooklyn.entity.proxy.ProxySslConfig;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 import com.google.common.collect.ImmutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/UrlMapping.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/UrlMapping.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/UrlMapping.java
index 8ccb4a2..a564121 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/UrlMapping.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/UrlMapping.java
@@ -27,10 +27,10 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.effector.MethodEffector;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.group.AbstractGroup;
 import org.apache.brooklyn.entity.proxy.AbstractController;
 import org.apache.brooklyn.entity.proxy.ProxySslConfig;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 import com.google.common.reflect.TypeToken;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java
index 85a7e97..47d2ee8 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java
@@ -32,12 +32,12 @@ import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.trait.MemberReplaceable;
 import org.apache.brooklyn.core.entity.trait.Resizable;
 import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.group.Cluster;
 import org.apache.brooklyn.entity.group.DynamicCluster;
 import org.apache.brooklyn.entity.group.DynamicGroup;
 import org.apache.brooklyn.entity.proxy.LoadBalancer;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppCluster.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppCluster.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppCluster.java
index 8daad8d..c1466d3 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppCluster.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppCluster.java
@@ -22,8 +22,8 @@ import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.config.render.RendererHints;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
 import org.apache.brooklyn.util.time.Duration;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppFabric.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppFabric.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppFabric.java
index 2f5fdf5..2feeed7 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppFabric.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppFabric.java
@@ -20,8 +20,8 @@ package org.apache.brooklyn.entity.webapp;
 
 import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
 import org.apache.brooklyn.entity.group.DynamicFabric;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
 
 /**
  * DynamicWebAppFabric provide a fabric of clusters, aggregating the entity attributes.  Currently totals and averages:

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/JavaWebAppService.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/JavaWebAppService.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/JavaWebAppService.java
index 650b1e9..4f3ca03 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/JavaWebAppService.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/JavaWebAppService.java
@@ -29,8 +29,8 @@ import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.annotation.EffectorParam;
 import org.apache.brooklyn.core.config.BasicConfigKey;
 import org.apache.brooklyn.core.effector.MethodEffector;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
 import org.apache.brooklyn.entity.java.UsesJava;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 public interface JavaWebAppService extends WebAppService, UsesJava {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/WebAppServiceConstants.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/WebAppServiceConstants.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/WebAppServiceConstants.java
index 09be36f..df9b92e 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/WebAppServiceConstants.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/WebAppServiceConstants.java
@@ -23,9 +23,9 @@ import java.util.Set;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.config.render.RendererHints;
 import org.apache.brooklyn.core.entity.Attributes;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 import com.google.common.collect.ImmutableSet;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/WebAppServiceMetrics.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/WebAppServiceMetrics.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/WebAppServiceMetrics.java
index 6319089..7264698 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/WebAppServiceMetrics.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/WebAppServiceMetrics.java
@@ -20,16 +20,16 @@ package org.apache.brooklyn.entity.webapp;
 
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.config.render.RendererHints;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.util.math.MathFunctions;
 import org.apache.brooklyn.util.text.ByteSizeStrings;
 import org.apache.brooklyn.util.time.Duration;
 
 public interface WebAppServiceMetrics {
     
-    public static final org.apache.brooklyn.sensor.core.BasicAttributeSensor<Integer> ERROR_COUNT =
-            new org.apache.brooklyn.sensor.core.BasicAttributeSensor<Integer>(Integer.class, "webapp.reqs.errors", "Request errors");
+    public static final org.apache.brooklyn.core.sensor.BasicAttributeSensor<Integer> ERROR_COUNT =
+            new org.apache.brooklyn.core.sensor.BasicAttributeSensor<Integer>(Integer.class, "webapp.reqs.errors", "Request errors");
     public static final AttributeSensor<Integer> TOTAL_PROCESSING_TIME = Sensors.newIntegerSensor(
             "webapp.reqs.processingTime.total", "Total processing time, reported by webserver (millis)");
     public static final AttributeSensor<Integer> MAX_PROCESSING_TIME =

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6Server.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6Server.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6Server.java
index 3e3419d..4b2da35 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6Server.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6Server.java
@@ -22,10 +22,10 @@ import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 @Catalog(name="JBoss Application Server 6", description="AS6: an open source Java application server from JBoss", iconUrl="classpath:///jboss-logo.png")

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7Server.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7Server.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7Server.java
index 5fc7a23..6a67e45 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7Server.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7Server.java
@@ -24,12 +24,12 @@ import org.apache.brooklyn.api.objs.HasShortName;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.javalang.JavaClassNames;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jetty/Jetty6Server.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jetty/Jetty6Server.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jetty/Jetty6Server.java
index 1bce7e7..c0fdf2c 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jetty/Jetty6Server.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jetty/Jetty6Server.java
@@ -24,11 +24,11 @@ import org.apache.brooklyn.api.objs.HasShortName;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/tomcat/Tomcat8Server.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/tomcat/Tomcat8Server.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/tomcat/Tomcat8Server.java
index d9e2f7f..19a70c9 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/tomcat/Tomcat8Server.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/tomcat/Tomcat8Server.java
@@ -22,8 +22,8 @@ import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.javalang.JavaClassNames;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/tomcat/TomcatServer.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/tomcat/TomcatServer.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/tomcat/TomcatServer.java
index 332c277..72ff1eb 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/tomcat/TomcatServer.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/tomcat/TomcatServer.java
@@ -25,12 +25,12 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.javalang.JavaClassNames;
 import org.apache.brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/StubAppServer.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/StubAppServer.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/StubAppServer.java
index 3e8b604..2d75f98 100644
--- a/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/StubAppServer.java
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/StubAppServer.java
@@ -31,7 +31,7 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.collections.MutableMap;
 
 import com.google.common.base.Throwables;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/nginx/NginxHttpsSslIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/nginx/NginxHttpsSslIntegrationTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/nginx/NginxHttpsSslIntegrationTest.java
index b8e5516..abaa2d6 100644
--- a/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/nginx/NginxHttpsSslIntegrationTest.java
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/nginx/NginxHttpsSslIntegrationTest.java
@@ -28,6 +28,7 @@ import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport;
 import org.apache.brooklyn.entity.group.DynamicCluster;
 import org.apache.brooklyn.entity.proxy.LoadBalancer;
@@ -36,7 +37,6 @@ import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.webapp.JavaWebAppService;
 import org.apache.brooklyn.entity.webapp.WebAppService;
 import org.apache.brooklyn.entity.webapp.jboss.JBoss7Server;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.test.HttpTestUtils;
 import org.apache.brooklyn.test.support.TestResourceUnavailableException;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/usage/archetypes/quickstart/src/brooklyn-sample/src/main/java/com/acme/sample/brooklyn/sample/app/ClusterWebServerDatabaseSample.java
----------------------------------------------------------------------
diff --git a/usage/archetypes/quickstart/src/brooklyn-sample/src/main/java/com/acme/sample/brooklyn/sample/app/ClusterWebServerDatabaseSample.java b/usage/archetypes/quickstart/src/brooklyn-sample/src/main/java/com/acme/sample/brooklyn/sample/app/ClusterWebServerDatabaseSample.java
index 6f2907b..bc53541 100644
--- a/usage/archetypes/quickstart/src/brooklyn-sample/src/main/java/com/acme/sample/brooklyn/sample/app/ClusterWebServerDatabaseSample.java
+++ b/usage/archetypes/quickstart/src/brooklyn-sample/src/main/java/com/acme/sample/brooklyn/sample/app/ClusterWebServerDatabaseSample.java
@@ -11,6 +11,7 @@ import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.AbstractApplication;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
 import org.apache.brooklyn.entity.database.mysql.MySqlNode;
 import org.apache.brooklyn.entity.group.DynamicCluster;
@@ -22,7 +23,6 @@ import org.apache.brooklyn.entity.webapp.WebAppService;
 import org.apache.brooklyn.entity.webapp.WebAppServiceConstants;
 import org.apache.brooklyn.policy.autoscaling.AutoScalerPolicy;
 import org.apache.brooklyn.policy.enricher.HttpLatencyDetector;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.enricher.SensorPropagatingEnricher;
 import org.apache.brooklyn.sensor.enricher.SensorTransformingEnricher;
 import org.apache.brooklyn.util.maven.MavenArtifact;
@@ -32,8 +32,8 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Functions;
 
-import static org.apache.brooklyn.sensor.core.DependentConfiguration.attributeWhenReady;
-import static org.apache.brooklyn.sensor.core.DependentConfiguration.formatString;
+import static org.apache.brooklyn.core.sensor.DependentConfiguration.attributeWhenReady;
+import static org.apache.brooklyn.core.sensor.DependentConfiguration.formatString;
 
 
 /** This sample builds a 3-tier application with an elastic app-server cluster,

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
index 906cbca..52122bf 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
@@ -35,7 +35,7 @@ import org.apache.brooklyn.camp.brooklyn.spi.dsl.BrooklynDslDeferredSupplier;
 import org.apache.brooklyn.camp.brooklyn.spi.dsl.DslUtils;
 import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent.Scope;
 import org.apache.brooklyn.core.entity.EntityDynamicType;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.flags.ClassCoercionException;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
index c5dd80c..eebc628 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
@@ -34,8 +34,8 @@ import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.EntityPredicates;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
 import org.apache.brooklyn.core.mgmt.internal.EntityManagerInternal;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.util.core.task.TaskBuilder;
 import org.apache.brooklyn.util.core.task.Tasks;
 import org.apache.brooklyn.util.guava.Maybe;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/DslAndRebindYamlTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/DslAndRebindYamlTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/DslAndRebindYamlTest.java
index 026eeee..79addd4 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/DslAndRebindYamlTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/DslAndRebindYamlTest.java
@@ -33,8 +33,8 @@ import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
 import org.apache.brooklyn.core.mgmt.rebind.RebindTestUtils;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.task.Tasks;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/EnrichersSlightlySimplerYamlTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/EnrichersSlightlySimplerYamlTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/EnrichersSlightlySimplerYamlTest.java
index 2a2fe6b..6816ce2 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/EnrichersSlightlySimplerYamlTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/EnrichersSlightlySimplerYamlTest.java
@@ -27,9 +27,9 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.group.DynamicCluster;
 import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcess;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.collections.CollectionFunctionals;
 import org.apache.brooklyn.util.collections.MutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java
index f9fe108..6dd636d 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java
@@ -49,12 +49,12 @@ import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.EntityPredicates;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.mgmt.internal.EntityManagerInternal;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.core.test.entity.TestEntityImpl;
 import org.apache.brooklyn.entity.group.DynamicCluster;
 import org.apache.brooklyn.entity.software.base.SameServerEntity;
 import org.apache.brooklyn.entity.stock.BasicEntity;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.task.Tasks;
 import org.apache.brooklyn.util.exceptions.Exceptions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/TestSensorAndEffectorInitializer.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/TestSensorAndEffectorInitializer.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/TestSensorAndEffectorInitializer.java
index 85b67af..67f7369 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/TestSensorAndEffectorInitializer.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/TestSensorAndEffectorInitializer.java
@@ -27,7 +27,7 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.effector.EffectorBody;
 import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.testng.Assert;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/VanillaBashNetcatYamlTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/VanillaBashNetcatYamlTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/VanillaBashNetcatYamlTest.java
index f3f0e50..52dd4cc 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/VanillaBashNetcatYamlTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/VanillaBashNetcatYamlTest.java
@@ -28,7 +28,7 @@ import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityPredicates;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.net.Networking;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedTheeTierApp.java
----------------------------------------------------------------------
diff --git a/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedTheeTierApp.java b/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedTheeTierApp.java
index 9e3e1cd..3c191a1 100644
--- a/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedTheeTierApp.java
+++ b/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedTheeTierApp.java
@@ -18,8 +18,8 @@
  */
 package org.apache.brooklyn.qa.load;
 
-import static org.apache.brooklyn.sensor.core.DependentConfiguration.attributeWhenReady;
-import static org.apache.brooklyn.sensor.core.DependentConfiguration.formatString;
+import static org.apache.brooklyn.core.sensor.DependentConfiguration.attributeWhenReady;
+import static org.apache.brooklyn.core.sensor.DependentConfiguration.formatString;
 
 import java.util.Collection;
 import java.util.List;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/usage/qa/src/test/java/org/apache/brooklyn/qa/longevity/webcluster/WebClusterApp.java
----------------------------------------------------------------------
diff --git a/usage/qa/src/test/java/org/apache/brooklyn/qa/longevity/webcluster/WebClusterApp.java b/usage/qa/src/test/java/org/apache/brooklyn/qa/longevity/webcluster/WebClusterApp.java
index 136bbf5..f43cdcb 100644
--- a/usage/qa/src/test/java/org/apache/brooklyn/qa/longevity/webcluster/WebClusterApp.java
+++ b/usage/qa/src/test/java/org/apache/brooklyn/qa/longevity/webcluster/WebClusterApp.java
@@ -27,12 +27,12 @@ import org.apache.brooklyn.core.entity.AbstractApplication;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.StartableApplication;
 import org.apache.brooklyn.core.internal.BrooklynProperties;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.proxy.nginx.NginxController;
 import org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster;
 import org.apache.brooklyn.entity.webapp.jboss.JBoss7Server;
 import org.apache.brooklyn.launcher.BrooklynLauncher;
 import org.apache.brooklyn.policy.autoscaling.AutoScalerPolicy;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.util.CommandLineUtil;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/ApplicationResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/ApplicationResource.java b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/ApplicationResource.java
index b084505..5bc8df9 100644
--- a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/ApplicationResource.java
+++ b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/ApplicationResource.java
@@ -55,6 +55,7 @@ import org.apache.brooklyn.core.mgmt.entitlement.EntitlementPredicates;
 import org.apache.brooklyn.core.mgmt.entitlement.Entitlements;
 import org.apache.brooklyn.core.mgmt.entitlement.Entitlements.EntityAndItem;
 import org.apache.brooklyn.core.mgmt.entitlement.Entitlements.StringAndArgument;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.group.AbstractGroup;
 import org.apache.brooklyn.rest.api.ApplicationApi;
 import org.apache.brooklyn.rest.domain.ApplicationSpec;
@@ -67,7 +68,6 @@ import org.apache.brooklyn.rest.transform.EntityTransformer;
 import org.apache.brooklyn.rest.transform.TaskTransformer;
 import org.apache.brooklyn.rest.util.BrooklynRestResourceUtils;
 import org.apache.brooklyn.rest.util.WebResourceUtils;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.exceptions.Exceptions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/SensorResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/SensorResource.java b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/SensorResource.java
index c645874..1976d6f 100644
--- a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/SensorResource.java
+++ b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/SensorResource.java
@@ -31,12 +31,12 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.Sensor;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.mgmt.entitlement.Entitlements;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
 import org.apache.brooklyn.rest.api.SensorApi;
 import org.apache.brooklyn.rest.domain.SensorSummary;
 import org.apache.brooklyn.rest.filter.HaHotStateRequired;
 import org.apache.brooklyn.rest.transform.SensorTransformer;
 import org.apache.brooklyn.rest.util.WebResourceUtils;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
 import org.apache.brooklyn.util.core.task.ValueResolver;
 import org.apache.brooklyn.util.text.Strings;
 import org.apache.brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/usage/rest-server/src/test/java/org/apache/brooklyn/rest/domain/SensorSummaryTest.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/domain/SensorSummaryTest.java b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/domain/SensorSummaryTest.java
index c144117..0355def 100644
--- a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/domain/SensorSummaryTest.java
+++ b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/domain/SensorSummaryTest.java
@@ -35,10 +35,10 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.Sensor;
 import org.apache.brooklyn.core.config.render.RendererHints;
 import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.rest.transform.SensorTransformer;
-import org.apache.brooklyn.sensor.core.Sensors;
 
 import com.google.common.collect.ImmutableMap;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/DescendantsTest.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/DescendantsTest.java b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/DescendantsTest.java
index 3a6eb32..8e11d82 100644
--- a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/DescendantsTest.java
+++ b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/DescendantsTest.java
@@ -35,12 +35,12 @@ import org.testng.annotations.Test;
 import org.apache.brooklyn.api.entity.Application;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.rest.domain.ApplicationSpec;
 import org.apache.brooklyn.rest.domain.EntitySpec;
 import org.apache.brooklyn.rest.domain.EntitySummary;
 import org.apache.brooklyn.rest.testing.BrooklynRestResourceTest;
 import org.apache.brooklyn.rest.testing.mocks.RestMockSimpleEntity;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.text.StringEscapes;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/SensorResourceTest.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/SensorResourceTest.java b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/SensorResourceTest.java
index 8d02369..ad606c7 100644
--- a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/SensorResourceTest.java
+++ b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/SensorResourceTest.java
@@ -29,13 +29,13 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.config.render.RendererHints;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.EntityPredicates;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.rest.api.SensorApi;
 import org.apache.brooklyn.rest.domain.ApplicationSpec;
 import org.apache.brooklyn.rest.domain.EntitySpec;
 import org.apache.brooklyn.rest.test.config.render.TestRendererHints;
 import org.apache.brooklyn.rest.testing.BrooklynRestResourceTest;
 import org.apache.brooklyn.rest.testing.mocks.RestMockSimpleEntity;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.test.HttpTestUtils;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.stream.Streams;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/RestMockSimpleEntity.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/RestMockSimpleEntity.java b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/RestMockSimpleEntity.java
index e680bc1..2983f4e 100644
--- a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/RestMockSimpleEntity.java
+++ b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/RestMockSimpleEntity.java
@@ -28,12 +28,12 @@ import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.annotation.EffectorParam;
 import org.apache.brooklyn.core.config.BasicConfigKey;
 import org.apache.brooklyn.core.effector.MethodEffector;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
 import org.apache.brooklyn.entity.software.base.AbstractSoftwareProcessSshDriver;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 public class RestMockSimpleEntity extends SoftwareProcessImpl {


[03/36] incubator-brooklyn git commit: Move SshEffectorTasks into core’s effector.ssh package

Posted by he...@apache.org.
Move SshEffectorTasks into core’s effector.ssh package

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

Branch: refs/heads/master
Commit: 4820fa46722e980f3b90b55849977c3b115492e0
Parents: 0eab0fa
Author: Aled Sage <al...@gmail.com>
Authored: Wed Aug 19 22:35:40 2015 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Wed Aug 19 22:35:40 2015 +0100

----------------------------------------------------------------------
 .../effector/core/ssh/SshEffectorTasks.java     | 334 +++++++++++++++++++
 .../util/core/task/ssh/SshEffectorTasks.java    | 329 ------------------
 .../brooklyn/util/core/task/ssh/SshTasks.java   |   1 +
 .../effector/core/ssh/SshEffectorTasksTest.java | 264 +++++++++++++++
 .../core/task/ssh/SshEffectorTasksTest.java     | 264 ---------------
 .../util/core/task/ssh/SshTasksTest.java        |   1 +
 .../brooklyn/demo/CumulusRDFApplication.java    |   2 +-
 .../postgresql/PostgreSqlNodeSaltImpl.java      |   2 +-
 .../entity/salt/SaltLifecycleEffectorTasks.java |   2 +-
 .../apache/brooklyn/entity/salt/SaltTasks.java  |   2 +-
 .../postgresql/PostgreSqlSaltLiveTest.java      |   2 +-
 .../brooklynnode/BrooklynNodeSshDriver.java     |   2 +-
 .../BrooklynNodeUpgradeEffectorBody.java        |   2 +-
 .../entity/chef/ChefLifecycleEffectorTasks.java |   2 +-
 .../brooklyn/entity/chef/ChefSoloTasks.java     |   2 +-
 .../apache/brooklyn/entity/chef/ChefTasks.java  |   2 +-
 .../java/JavaSoftwareProcessSshDriver.java      |   2 +-
 .../entity/machine/MachineEntityImpl.java       |   2 +-
 .../base/AbstractSoftwareProcessSshDriver.java  |   2 +-
 .../MachineLifecycleEffectorTasks.java          |   2 +-
 .../brooklyn/sensor/ssh/SshCommandEffector.java |   4 +-
 .../ChefSoloDriverMySqlEntityLiveTest.java      |   2 +-
 .../mysql/ChefSoloDriverToyMySqlEntity.java     |   2 +-
 .../software/base/SoftwareEffectorTest.java     |   4 +-
 .../test/mysql/AbstractToyMySqlEntityTest.java  |   2 +-
 .../mysql/DynamicToyMySqlEntityBuilder.java     |   2 +-
 .../database/mariadb/MariaDbSshDriver.java      |   2 +-
 .../entity/database/mysql/MySqlSshDriver.java   |   2 +-
 .../PostgreSqlNodeChefImplFromScratch.java      |   2 +-
 .../postgresql/PostgreSqlSshDriver.java         |   2 +-
 .../database/postgresql/PostgreSqlChefTest.java |   2 +-
 .../nosql/cassandra/CassandraNodeSshDriver.java |   2 +-
 .../nosql/couchbase/CouchbaseNodeSshDriver.java |   2 +-
 .../entity/nosql/riak/RiakNodeSshDriver.java    |   2 +-
 .../entity/osgi/karaf/KarafContainerTest.java   |   2 +-
 .../qa/load/SimulatedMySqlNodeImpl.java         |   2 +-
 36 files changed, 632 insertions(+), 625 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/core/src/main/java/org/apache/brooklyn/effector/core/ssh/SshEffectorTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/effector/core/ssh/SshEffectorTasks.java b/core/src/main/java/org/apache/brooklyn/effector/core/ssh/SshEffectorTasks.java
new file mode 100644
index 0000000..b904ba7
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/effector/core/ssh/SshEffectorTasks.java
@@ -0,0 +1,334 @@
+/*
+ * 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.effector.core.ssh;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.config.StringConfigMap;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.config.ConfigUtils;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.location.internal.LocationInternal;
+import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.effector.core.EffectorBody;
+import org.apache.brooklyn.effector.core.EffectorTasks;
+import org.apache.brooklyn.effector.core.EffectorTasks.EffectorTaskFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.core.internal.ssh.SshTool;
+import org.apache.brooklyn.util.core.task.Tasks;
+import org.apache.brooklyn.util.core.task.ssh.SshFetchTaskFactory;
+import org.apache.brooklyn.util.core.task.ssh.SshFetchTaskWrapper;
+import org.apache.brooklyn.util.core.task.ssh.SshPutTaskFactory;
+import org.apache.brooklyn.util.core.task.ssh.SshPutTaskWrapper;
+import org.apache.brooklyn.util.core.task.ssh.SshTasks;
+import org.apache.brooklyn.util.core.task.ssh.internal.AbstractSshExecTaskFactory;
+import org.apache.brooklyn.util.core.task.ssh.internal.PlainSshExecTaskFactory;
+import org.apache.brooklyn.util.core.task.system.ProcessTaskFactory;
+import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.util.ssh.BashCommands;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.common.collect.Maps;
+
+/**
+ * Conveniences for generating {@link Task} instances to perform SSH activities.
+ * <p>
+ * If the {@link SshMachineLocation machine} is not specified directly it
+ * will be inferred from the {@link Entity} context of either the {@link Effector}
+ * or the current {@link Task}.
+ * 
+ * @see SshTasks
+ * @since 0.6.0
+ */
+@Beta
+public class SshEffectorTasks {
+
+    private static final Logger log = LoggerFactory.getLogger(SshEffectorTasks.class);
+    
+    public static final ConfigKey<Boolean> IGNORE_ENTITY_SSH_FLAGS = ConfigKeys.newBooleanConfigKey("ignoreEntitySshFlags",
+        "Whether to ignore any ssh flags (behaviour constraints) set on the entity or location " +
+        "where this is running, using only flags explicitly specified", false);
+    
+    /**
+     * Like {@link EffectorBody} but providing conveniences when in an entity with a single machine location.
+     */
+    public abstract static class SshEffectorBody<T> extends EffectorBody<T> {
+        
+        /** convenience for accessing the machine */
+        public SshMachineLocation machine() {
+            return EffectorTasks.getSshMachine(entity());
+        }
+
+        /** convenience for generating an {@link PlainSshExecTaskFactory} which can be further customised if desired, and then (it must be explicitly) queued */
+        public ProcessTaskFactory<Integer> ssh(String ...commands) {
+            return new SshEffectorTaskFactory<Integer>(commands).machine(machine());
+        }
+    }
+
+    /** variant of {@link PlainSshExecTaskFactory} which fulfills the {@link EffectorTaskFactory} signature so can be used directly as an impl for an effector,
+     * also injects the machine automatically; can also be used outwith effector contexts, and machine is still injected if it is
+     * run from inside a task at an entity with a single SshMachineLocation */
+    public static class SshEffectorTaskFactory<RET> extends AbstractSshExecTaskFactory<SshEffectorTaskFactory<RET>,RET> implements EffectorTaskFactory<RET> {
+
+        public SshEffectorTaskFactory(String ...commands) {
+            super(commands);
+        }
+        public SshEffectorTaskFactory(SshMachineLocation machine, String ...commands) {
+            super(machine, commands);
+        }
+        @Override
+        public ProcessTaskWrapper<RET> newTask(Entity entity, Effector<RET> effector, ConfigBag parameters) {
+            markDirty();
+            if (summary==null) summary(effector.getName()+" (ssh)");
+            machine(EffectorTasks.getSshMachine(entity));
+            return newTask();
+        }
+        @Override
+        public synchronized ProcessTaskWrapper<RET> newTask() {
+            Entity entity = BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
+            if (machine==null) {
+                if (log.isDebugEnabled())
+                    log.debug("Using an ssh task not in an effector without any machine; will attempt to infer the machine: "+this);
+                if (entity!=null)
+                    machine(EffectorTasks.getSshMachine(entity));
+            }
+            applySshFlags(getConfig(), entity, getMachine());
+            return super.newTask();
+        }
+        
+        @Override
+        public <T2> SshEffectorTaskFactory<T2> returning(ScriptReturnType type) {
+            return (SshEffectorTaskFactory<T2>) super.<T2>returning(type);
+        }
+
+        @Override
+        public SshEffectorTaskFactory<Boolean> returningIsExitCodeZero() {
+            return (SshEffectorTaskFactory<Boolean>) super.returningIsExitCodeZero();
+        }
+
+        public SshEffectorTaskFactory<String> requiringZeroAndReturningStdout() {
+            return (SshEffectorTaskFactory<String>) super.requiringZeroAndReturningStdout();
+        }
+        
+        public <RET2> SshEffectorTaskFactory<RET2> returning(Function<ProcessTaskWrapper<?>, RET2> resultTransformation) {
+            return (SshEffectorTaskFactory<RET2>) super.returning(resultTransformation);
+        }
+    }
+    
+    public static class SshPutEffectorTaskFactory extends SshPutTaskFactory implements EffectorTaskFactory<Void> {
+        public SshPutEffectorTaskFactory(String remoteFile) {
+            super(remoteFile);
+        }
+        public SshPutEffectorTaskFactory(SshMachineLocation machine, String remoteFile) {
+            super(machine, remoteFile);
+        }
+        @Override
+        public SshPutTaskWrapper newTask(Entity entity, Effector<Void> effector, ConfigBag parameters) {
+            machine(EffectorTasks.getSshMachine(entity));
+            applySshFlags(getConfig(), entity, getMachine());
+            return super.newTask();
+        }
+        @Override
+        public SshPutTaskWrapper newTask() {
+            Entity entity = BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
+            if (machine==null) {
+                if (log.isDebugEnabled())
+                    log.debug("Using an ssh put task not in an effector without any machine; will attempt to infer the machine: "+this);
+                if (entity!=null) {
+                    machine(EffectorTasks.getSshMachine(entity));
+                }
+
+            }
+            applySshFlags(getConfig(), entity, getMachine());
+            return super.newTask();
+        }
+    }
+
+    public static class SshFetchEffectorTaskFactory extends SshFetchTaskFactory implements EffectorTaskFactory<String> {
+        public SshFetchEffectorTaskFactory(String remoteFile) {
+            super(remoteFile);
+        }
+        public SshFetchEffectorTaskFactory(SshMachineLocation machine, String remoteFile) {
+            super(machine, remoteFile);
+        }
+        @Override
+        public SshFetchTaskWrapper newTask(Entity entity, Effector<String> effector, ConfigBag parameters) {
+            machine(EffectorTasks.getSshMachine(entity));
+            applySshFlags(getConfig(), entity, getMachine());
+            return super.newTask();
+        }
+        @Override
+        public SshFetchTaskWrapper newTask() {
+            Entity entity = BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
+            if (machine==null) {
+                if (log.isDebugEnabled())
+                    log.debug("Using an ssh fetch task not in an effector without any machine; will attempt to infer the machine: "+this);
+                if (entity!=null)
+                    machine(EffectorTasks.getSshMachine(entity));
+            }
+            applySshFlags(getConfig(), entity, getMachine());
+            return super.newTask();
+        }
+    }
+
+    public static SshEffectorTaskFactory<Integer> ssh(String ...commands) {
+        return new SshEffectorTaskFactory<Integer>(commands);
+    }
+
+    public static SshEffectorTaskFactory<Integer> ssh(List<String> commands) {
+        return ssh(commands.toArray(new String[commands.size()]));
+    }
+
+    public static SshPutTaskFactory put(String remoteFile) {
+        return new SshPutEffectorTaskFactory(remoteFile);
+    }
+
+    public static SshFetchEffectorTaskFactory fetch(String remoteFile) {
+        return new SshFetchEffectorTaskFactory(remoteFile);
+    }
+
+    /** task which returns 0 if pid is running */
+    public static SshEffectorTaskFactory<Integer> codePidRunning(Integer pid) {
+        return ssh("ps -p "+pid).summary("PID "+pid+" is-running check (exit code)").allowingNonZeroExitCode();
+    }
+    
+    /** task which fails if the given PID is not running */
+    public static SshEffectorTaskFactory<?> requirePidRunning(Integer pid) {
+        return codePidRunning(pid).summary("PID "+pid+" is-running check (required)").requiringExitCodeZero("Process with PID "+pid+" is required to be running");
+    }
+
+    /** as {@link #codePidRunning(Integer)} but returning boolean */
+    public static SshEffectorTaskFactory<Boolean> isPidRunning(Integer pid) {
+        return codePidRunning(pid).summary("PID "+pid+" is-running check (boolean)").returning(new Function<ProcessTaskWrapper<?>, Boolean>() {
+            public Boolean apply(@Nullable ProcessTaskWrapper<?> input) { return Integer.valueOf(0).equals(input.getExitCode()); }
+        });
+    }
+
+
+    /** task which returns 0 if pid in the given file is running;
+     * method accepts wildcards so long as they match a single file on the remote end
+     * <p>
+     * returns 1 if no matching file, 
+     * 1 if matching file but no matching process,
+     * and 2 if 2+ matching files */
+    public static SshEffectorTaskFactory<Integer> codePidFromFileRunning(final String pidFile) {
+        return ssh(BashCommands.chain(
+                // this fails, but isn't an error
+                BashCommands.requireTest("-f "+pidFile, "The PID file "+pidFile+" does not exist."),
+                // this fails and logs an error picked up later
+                BashCommands.requireTest("`ls "+pidFile+" | wc -w` -eq 1", "ERROR: there are multiple matching PID files"),
+                // this fails and logs an error picked up later
+                BashCommands.require("cat "+pidFile, "ERROR: the PID file "+pidFile+" cannot be read (permissions?)."),
+                // finally check the process
+                "ps -p `cat "+pidFile+"`")).summary("PID file "+pidFile+" is-running check (exit code)")
+                .allowingNonZeroExitCode()
+                .addCompletionListener(new Function<ProcessTaskWrapper<?>,Void>() {
+                    public Void apply(ProcessTaskWrapper<?> input) {
+                        if (input.getStderr().contains("ERROR:"))
+                            throw new IllegalStateException("Invalid or inaccessible PID filespec: "+pidFile);
+                        return null;
+                    }
+                });
+    }
+    
+    /** task which fails if the pid in the given file is not running (or if there is no such PID file);
+     * method accepts wildcards so long as they match a single file on the remote end (fails if 0 or 2+ matching files) */
+    public static SshEffectorTaskFactory<?> requirePidFromFileRunning(String pidFile) {
+        return codePidFromFileRunning(pidFile)
+                .summary("PID file "+pidFile+" is-running check (required)")
+                .requiringExitCodeZero("Process with PID from file "+pidFile+" is required to be running");
+    }
+
+    /** as {@link #codePidFromFileRunning(String)} but returning boolean */
+    public static SshEffectorTaskFactory<Boolean> isPidFromFileRunning(String pidFile) {
+        return codePidFromFileRunning(pidFile).summary("PID file "+pidFile+" is-running check (boolean)").
+                returning(new Function<ProcessTaskWrapper<?>, Boolean>() {
+                    public Boolean apply(@Nullable ProcessTaskWrapper<?> input) { return ((Integer)0).equals(input.getExitCode()); }
+                });
+    }
+
+    /** extracts the values for the main brooklyn.ssh.config.* config keys (i.e. those declared in ConfigKeys) 
+     * as declared on the entity, and inserts them in a map using the unprefixed state, for ssh.
+     * <p>
+     * currently this is computed for each call, which may be wasteful, but it is reliable in the face of config changes.
+     * we could cache the Map.  note that we do _not_ cache (or even own) the SshTool; 
+     * the SshTool is created or re-used by the SshMachineLocation making use of these properties */
+    @Beta
+    public static Map<String, Object> getSshFlags(Entity entity, Location optionalLocation) {
+        ConfigBag allConfig = ConfigBag.newInstance();
+        
+        StringConfigMap globalConfig = ((EntityInternal)entity).getManagementContext().getConfig();
+        allConfig.putAll(globalConfig.getAllConfig());
+        
+        if (optionalLocation!=null)
+            allConfig.putAll(((LocationInternal)optionalLocation).config().getBag());
+        
+        allConfig.putAll(((EntityInternal)entity).getAllConfig());
+        
+        Map<String, Object> result = Maps.newLinkedHashMap();
+        for (String keyS : allConfig.getAllConfig().keySet()) {
+            if (keyS.startsWith(SshTool.BROOKLYN_CONFIG_KEY_PREFIX)) {
+                ConfigKey<?> key = ConfigKeys.newConfigKey(Object.class, keyS);
+                
+                Object val = allConfig.getStringKey(keyS);
+                
+                /*
+                 * NOV 2013 changing this to rely on config above being inserted in the right order,
+                 * so entity config will be preferred over location, and location over global.
+                 * If that is consistent then remove the lines below.
+                 * (We can also accept null entity and so combine with SshTasks.getSshFlags.)
+                 */
+                
+//                // have to use raw config to test whether the config is set
+//                Object val = ((EntityInternal)entity).getConfigMap().getRawConfig(key);
+//                if (val!=null) {
+//                    val = entity.getConfig(key);
+//                } else {
+//                    val = globalConfig.getRawConfig(key);
+//                    if (val!=null) val = globalConfig.getConfig(key);
+//                }
+//                if (val!=null) {
+                    result.put(ConfigUtils.unprefixedKey(SshTool.BROOKLYN_CONFIG_KEY_PREFIX, key).getName(), val);
+//                }
+            }
+        }
+        return result;
+    }
+
+    private static void applySshFlags(ConfigBag config, Entity entity, Location machine) {
+        if (entity!=null) {
+            if (!config.get(IGNORE_ENTITY_SSH_FLAGS)) {
+                config.putIfAbsent(getSshFlags(entity, machine));
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshEffectorTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshEffectorTasks.java b/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshEffectorTasks.java
deleted file mode 100644
index 849cd25..0000000
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshEffectorTasks.java
+++ /dev/null
@@ -1,329 +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.util.core.task.ssh;
-
-import java.util.List;
-import java.util.Map;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.mgmt.Task;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.config.StringConfigMap;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.config.ConfigUtils;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.core.location.internal.LocationInternal;
-import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.effector.core.EffectorBody;
-import org.apache.brooklyn.effector.core.EffectorTasks;
-import org.apache.brooklyn.effector.core.EffectorTasks.EffectorTaskFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.core.internal.ssh.SshTool;
-import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.core.task.ssh.internal.AbstractSshExecTaskFactory;
-import org.apache.brooklyn.util.core.task.ssh.internal.PlainSshExecTaskFactory;
-import org.apache.brooklyn.util.core.task.system.ProcessTaskFactory;
-import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
-import org.apache.brooklyn.util.ssh.BashCommands;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Function;
-import com.google.common.collect.Maps;
-
-/**
- * Conveniences for generating {@link Task} instances to perform SSH activities.
- * <p>
- * If the {@link SshMachineLocation machine} is not specified directly it
- * will be inferred from the {@link Entity} context of either the {@link Effector}
- * or the current {@link Task}.
- * 
- * @see SshTasks
- * @since 0.6.0
- */
-@Beta
-public class SshEffectorTasks {
-
-    private static final Logger log = LoggerFactory.getLogger(SshEffectorTasks.class);
-    
-    public static final ConfigKey<Boolean> IGNORE_ENTITY_SSH_FLAGS = ConfigKeys.newBooleanConfigKey("ignoreEntitySshFlags",
-        "Whether to ignore any ssh flags (behaviour constraints) set on the entity or location " +
-        "where this is running, using only flags explicitly specified", false);
-    
-    /**
-     * Like {@link EffectorBody} but providing conveniences when in an entity with a single machine location.
-     */
-    public abstract static class SshEffectorBody<T> extends EffectorBody<T> {
-        
-        /** convenience for accessing the machine */
-        public SshMachineLocation machine() {
-            return EffectorTasks.getSshMachine(entity());
-        }
-
-        /** convenience for generating an {@link PlainSshExecTaskFactory} which can be further customised if desired, and then (it must be explicitly) queued */
-        public ProcessTaskFactory<Integer> ssh(String ...commands) {
-            return new SshEffectorTaskFactory<Integer>(commands).machine(machine());
-        }
-    }
-
-    /** variant of {@link PlainSshExecTaskFactory} which fulfills the {@link EffectorTaskFactory} signature so can be used directly as an impl for an effector,
-     * also injects the machine automatically; can also be used outwith effector contexts, and machine is still injected if it is
-     * run from inside a task at an entity with a single SshMachineLocation */
-    public static class SshEffectorTaskFactory<RET> extends AbstractSshExecTaskFactory<SshEffectorTaskFactory<RET>,RET> implements EffectorTaskFactory<RET> {
-
-        public SshEffectorTaskFactory(String ...commands) {
-            super(commands);
-        }
-        public SshEffectorTaskFactory(SshMachineLocation machine, String ...commands) {
-            super(machine, commands);
-        }
-        @Override
-        public ProcessTaskWrapper<RET> newTask(Entity entity, Effector<RET> effector, ConfigBag parameters) {
-            markDirty();
-            if (summary==null) summary(effector.getName()+" (ssh)");
-            machine(EffectorTasks.getSshMachine(entity));
-            return newTask();
-        }
-        @Override
-        public synchronized ProcessTaskWrapper<RET> newTask() {
-            Entity entity = BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
-            if (machine==null) {
-                if (log.isDebugEnabled())
-                    log.debug("Using an ssh task not in an effector without any machine; will attempt to infer the machine: "+this);
-                if (entity!=null)
-                    machine(EffectorTasks.getSshMachine(entity));
-            }
-            applySshFlags(getConfig(), entity, getMachine());
-            return super.newTask();
-        }
-        
-        @Override
-        public <T2> SshEffectorTaskFactory<T2> returning(ScriptReturnType type) {
-            return (SshEffectorTaskFactory<T2>) super.<T2>returning(type);
-        }
-
-        @Override
-        public SshEffectorTaskFactory<Boolean> returningIsExitCodeZero() {
-            return (SshEffectorTaskFactory<Boolean>) super.returningIsExitCodeZero();
-        }
-
-        public SshEffectorTaskFactory<String> requiringZeroAndReturningStdout() {
-            return (SshEffectorTaskFactory<String>) super.requiringZeroAndReturningStdout();
-        }
-        
-        public <RET2> SshEffectorTaskFactory<RET2> returning(Function<ProcessTaskWrapper<?>, RET2> resultTransformation) {
-            return (SshEffectorTaskFactory<RET2>) super.returning(resultTransformation);
-        }
-    }
-    
-    public static class SshPutEffectorTaskFactory extends SshPutTaskFactory implements EffectorTaskFactory<Void> {
-        public SshPutEffectorTaskFactory(String remoteFile) {
-            super(remoteFile);
-        }
-        public SshPutEffectorTaskFactory(SshMachineLocation machine, String remoteFile) {
-            super(machine, remoteFile);
-        }
-        @Override
-        public SshPutTaskWrapper newTask(Entity entity, Effector<Void> effector, ConfigBag parameters) {
-            machine(EffectorTasks.getSshMachine(entity));
-            applySshFlags(getConfig(), entity, getMachine());
-            return super.newTask();
-        }
-        @Override
-        public SshPutTaskWrapper newTask() {
-            Entity entity = BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
-            if (machine==null) {
-                if (log.isDebugEnabled())
-                    log.debug("Using an ssh put task not in an effector without any machine; will attempt to infer the machine: "+this);
-                if (entity!=null) {
-                    machine(EffectorTasks.getSshMachine(entity));
-                }
-
-            }
-            applySshFlags(getConfig(), entity, getMachine());
-            return super.newTask();
-        }
-    }
-
-    public static class SshFetchEffectorTaskFactory extends SshFetchTaskFactory implements EffectorTaskFactory<String> {
-        public SshFetchEffectorTaskFactory(String remoteFile) {
-            super(remoteFile);
-        }
-        public SshFetchEffectorTaskFactory(SshMachineLocation machine, String remoteFile) {
-            super(machine, remoteFile);
-        }
-        @Override
-        public SshFetchTaskWrapper newTask(Entity entity, Effector<String> effector, ConfigBag parameters) {
-            machine(EffectorTasks.getSshMachine(entity));
-            applySshFlags(getConfig(), entity, getMachine());
-            return super.newTask();
-        }
-        @Override
-        public SshFetchTaskWrapper newTask() {
-            Entity entity = BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
-            if (machine==null) {
-                if (log.isDebugEnabled())
-                    log.debug("Using an ssh fetch task not in an effector without any machine; will attempt to infer the machine: "+this);
-                if (entity!=null)
-                    machine(EffectorTasks.getSshMachine(entity));
-            }
-            applySshFlags(getConfig(), entity, getMachine());
-            return super.newTask();
-        }
-    }
-
-    public static SshEffectorTaskFactory<Integer> ssh(String ...commands) {
-        return new SshEffectorTaskFactory<Integer>(commands);
-    }
-
-    public static SshEffectorTaskFactory<Integer> ssh(List<String> commands) {
-        return ssh(commands.toArray(new String[commands.size()]));
-    }
-
-    public static SshPutTaskFactory put(String remoteFile) {
-        return new SshPutEffectorTaskFactory(remoteFile);
-    }
-
-    public static SshFetchEffectorTaskFactory fetch(String remoteFile) {
-        return new SshFetchEffectorTaskFactory(remoteFile);
-    }
-
-    /** task which returns 0 if pid is running */
-    public static SshEffectorTaskFactory<Integer> codePidRunning(Integer pid) {
-        return ssh("ps -p "+pid).summary("PID "+pid+" is-running check (exit code)").allowingNonZeroExitCode();
-    }
-    
-    /** task which fails if the given PID is not running */
-    public static SshEffectorTaskFactory<?> requirePidRunning(Integer pid) {
-        return codePidRunning(pid).summary("PID "+pid+" is-running check (required)").requiringExitCodeZero("Process with PID "+pid+" is required to be running");
-    }
-
-    /** as {@link #codePidRunning(Integer)} but returning boolean */
-    public static SshEffectorTaskFactory<Boolean> isPidRunning(Integer pid) {
-        return codePidRunning(pid).summary("PID "+pid+" is-running check (boolean)").returning(new Function<ProcessTaskWrapper<?>, Boolean>() {
-            public Boolean apply(@Nullable ProcessTaskWrapper<?> input) { return Integer.valueOf(0).equals(input.getExitCode()); }
-        });
-    }
-
-
-    /** task which returns 0 if pid in the given file is running;
-     * method accepts wildcards so long as they match a single file on the remote end
-     * <p>
-     * returns 1 if no matching file, 
-     * 1 if matching file but no matching process,
-     * and 2 if 2+ matching files */
-    public static SshEffectorTaskFactory<Integer> codePidFromFileRunning(final String pidFile) {
-        return ssh(BashCommands.chain(
-                // this fails, but isn't an error
-                BashCommands.requireTest("-f "+pidFile, "The PID file "+pidFile+" does not exist."),
-                // this fails and logs an error picked up later
-                BashCommands.requireTest("`ls "+pidFile+" | wc -w` -eq 1", "ERROR: there are multiple matching PID files"),
-                // this fails and logs an error picked up later
-                BashCommands.require("cat "+pidFile, "ERROR: the PID file "+pidFile+" cannot be read (permissions?)."),
-                // finally check the process
-                "ps -p `cat "+pidFile+"`")).summary("PID file "+pidFile+" is-running check (exit code)")
-                .allowingNonZeroExitCode()
-                .addCompletionListener(new Function<ProcessTaskWrapper<?>,Void>() {
-                    public Void apply(ProcessTaskWrapper<?> input) {
-                        if (input.getStderr().contains("ERROR:"))
-                            throw new IllegalStateException("Invalid or inaccessible PID filespec: "+pidFile);
-                        return null;
-                    }
-                });
-    }
-    
-    /** task which fails if the pid in the given file is not running (or if there is no such PID file);
-     * method accepts wildcards so long as they match a single file on the remote end (fails if 0 or 2+ matching files) */
-    public static SshEffectorTaskFactory<?> requirePidFromFileRunning(String pidFile) {
-        return codePidFromFileRunning(pidFile)
-                .summary("PID file "+pidFile+" is-running check (required)")
-                .requiringExitCodeZero("Process with PID from file "+pidFile+" is required to be running");
-    }
-
-    /** as {@link #codePidFromFileRunning(String)} but returning boolean */
-    public static SshEffectorTaskFactory<Boolean> isPidFromFileRunning(String pidFile) {
-        return codePidFromFileRunning(pidFile).summary("PID file "+pidFile+" is-running check (boolean)").
-                returning(new Function<ProcessTaskWrapper<?>, Boolean>() {
-                    public Boolean apply(@Nullable ProcessTaskWrapper<?> input) { return ((Integer)0).equals(input.getExitCode()); }
-                });
-    }
-
-    /** extracts the values for the main brooklyn.ssh.config.* config keys (i.e. those declared in ConfigKeys) 
-     * as declared on the entity, and inserts them in a map using the unprefixed state, for ssh.
-     * <p>
-     * currently this is computed for each call, which may be wasteful, but it is reliable in the face of config changes.
-     * we could cache the Map.  note that we do _not_ cache (or even own) the SshTool; 
-     * the SshTool is created or re-used by the SshMachineLocation making use of these properties */
-    @Beta
-    public static Map<String, Object> getSshFlags(Entity entity, Location optionalLocation) {
-        ConfigBag allConfig = ConfigBag.newInstance();
-        
-        StringConfigMap globalConfig = ((EntityInternal)entity).getManagementContext().getConfig();
-        allConfig.putAll(globalConfig.getAllConfig());
-        
-        if (optionalLocation!=null)
-            allConfig.putAll(((LocationInternal)optionalLocation).config().getBag());
-        
-        allConfig.putAll(((EntityInternal)entity).getAllConfig());
-        
-        Map<String, Object> result = Maps.newLinkedHashMap();
-        for (String keyS : allConfig.getAllConfig().keySet()) {
-            if (keyS.startsWith(SshTool.BROOKLYN_CONFIG_KEY_PREFIX)) {
-                ConfigKey<?> key = ConfigKeys.newConfigKey(Object.class, keyS);
-                
-                Object val = allConfig.getStringKey(keyS);
-                
-                /*
-                 * NOV 2013 changing this to rely on config above being inserted in the right order,
-                 * so entity config will be preferred over location, and location over global.
-                 * If that is consistent then remove the lines below.
-                 * (We can also accept null entity and so combine with SshTasks.getSshFlags.)
-                 */
-                
-//                // have to use raw config to test whether the config is set
-//                Object val = ((EntityInternal)entity).getConfigMap().getRawConfig(key);
-//                if (val!=null) {
-//                    val = entity.getConfig(key);
-//                } else {
-//                    val = globalConfig.getRawConfig(key);
-//                    if (val!=null) val = globalConfig.getConfig(key);
-//                }
-//                if (val!=null) {
-                    result.put(ConfigUtils.unprefixedKey(SshTool.BROOKLYN_CONFIG_KEY_PREFIX, key).getName(), val);
-//                }
-            }
-        }
-        return result;
-    }
-
-    private static void applySshFlags(ConfigBag config, Entity entity, Location machine) {
-        if (entity!=null) {
-            if (!config.get(IGNORE_ENTITY_SSH_FLAGS)) {
-                config.putIfAbsent(getSshFlags(entity, machine));
-            }
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshTasks.java b/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshTasks.java
index 022b52b..10eea13 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshTasks.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshTasks.java
@@ -35,6 +35,7 @@ import org.apache.brooklyn.core.config.ConfigUtils;
 import org.apache.brooklyn.core.location.AbstractLocation;
 import org.apache.brooklyn.core.location.internal.LocationInternal;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/core/src/test/java/org/apache/brooklyn/effector/core/ssh/SshEffectorTasksTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/effector/core/ssh/SshEffectorTasksTest.java b/core/src/test/java/org/apache/brooklyn/effector/core/ssh/SshEffectorTasksTest.java
new file mode 100644
index 0000000..597d267
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/effector/core/ssh/SshEffectorTasksTest.java
@@ -0,0 +1,264 @@
+/*
+ * 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.effector.core.ssh;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.mgmt.TaskAdaptable;
+import org.apache.brooklyn.api.mgmt.TaskFactory;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
+import org.apache.brooklyn.util.core.task.ssh.SshFetchTaskWrapper;
+import org.apache.brooklyn.util.core.task.ssh.SshPutTaskWrapper;
+import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.util.exceptions.PropagatedRuntimeException;
+import org.apache.brooklyn.util.net.Urls;
+import org.apache.commons.io.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+
+import com.google.common.io.Files;
+
+public class SshEffectorTasksTest {
+
+    private static final Logger log = LoggerFactory.getLogger(SshEffectorTasksTest.class);
+    
+    TestApplication app;
+    ManagementContext mgmt;
+    SshMachineLocation host;
+    File tempDir;
+    
+    boolean failureExpected;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setup() throws Exception {
+        app = TestApplication.Factory.newManagedInstanceForTests();
+        mgmt = app.getManagementContext();
+        
+        LocalhostMachineProvisioningLocation lhc = mgmt.getLocationManager().createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class));
+        host = lhc.obtain();
+        app.start(Arrays.asList(host));
+        clearExpectedFailure();
+        tempDir = Files.createTempDir();
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (mgmt != null) Entities.destroyAll(mgmt);
+        mgmt = null;
+        FileUtils.deleteDirectory(tempDir);
+        checkExpectedFailure();
+    }
+
+    protected void checkExpectedFailure() {
+        if (failureExpected) {
+            clearExpectedFailure();
+            Assert.fail("Test should have thrown an exception but it did not.");
+        }
+    }
+    
+    protected void clearExpectedFailure() {
+        failureExpected = false;
+    }
+
+    protected void setExpectingFailure() {
+        failureExpected = true;
+    }
+    
+    public <T extends TaskAdaptable<?>> T submit(final TaskFactory<T> taskFactory) {
+        return Entities.submit(app, taskFactory);
+    }
+    
+    // ------------------- basic ssh
+    
+    @Test(groups="Integration")
+    public void testSshEchoHello() {
+        ProcessTaskWrapper<Integer> t = submit(SshEffectorTasks.ssh("sleep 1 ; echo hello world"));
+        Assert.assertFalse(t.isDone());
+        Assert.assertEquals(t.get(), (Integer)0);
+        Assert.assertEquals(t.getTask().getUnchecked(), (Integer)0);
+        Assert.assertEquals(t.getStdout().trim(), "hello world");
+    }
+
+    @Test(groups="Integration")
+    public void testSshPut() throws IOException {
+        String fn = Urls.mergePaths(tempDir.getPath(), "f1");
+        SshPutTaskWrapper t = submit(SshEffectorTasks.put(fn).contents("hello world"));
+        t.block();
+        Assert.assertEquals(FileUtils.readFileToString(new File(fn)), "hello world");
+        // and make sure this doesn't throw
+        Assert.assertTrue(t.isDone());
+        Assert.assertTrue(t.isSuccessful());
+        Assert.assertEquals(t.get(), null);
+        Assert.assertEquals(t.getExitCode(), (Integer)0);
+    }
+
+    @Test(groups="Integration")
+    public void testSshFetch() throws IOException {
+        String fn = Urls.mergePaths(tempDir.getPath(), "f2");
+        FileUtils.write(new File(fn), "hello fetched world");
+        
+        SshFetchTaskWrapper t = submit(SshEffectorTasks.fetch(fn));
+        t.block();
+        
+        Assert.assertTrue(t.isDone());
+        Assert.assertEquals(t.get(), "hello fetched world");
+    }
+
+    // ----------------- pid stuff
+    
+    @Test(groups="Integration")
+    public void testNonRunningPid() {
+        ProcessTaskWrapper<Integer> t = submit(SshEffectorTasks.codePidRunning(99999));
+        Assert.assertNotEquals(t.getTask().getUnchecked(), (Integer)0);
+        Assert.assertNotEquals(t.getExitCode(), (Integer)0);
+        ProcessTaskWrapper<Boolean> t2 = submit(SshEffectorTasks.isPidRunning(99999));
+        Assert.assertFalse(t2.getTask().getUnchecked());
+    }
+
+    @Test(groups="Integration")
+    public void testNonRunningPidRequired() {
+        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidRunning(99999));
+        setExpectingFailure();
+        try {
+            t.getTask().getUnchecked();
+        } catch (Exception e) {
+            log.info("The error if required PID is not found is: "+e);
+            clearExpectedFailure();
+            Assert.assertTrue(e.toString().contains("Process with PID"), "Expected nice clue in error but got: "+e);
+        }
+        checkExpectedFailure();
+    }
+
+    public static Integer getMyPid() {
+        try {
+            java.lang.management.RuntimeMXBean runtime = 
+                    java.lang.management.ManagementFactory.getRuntimeMXBean();
+            java.lang.reflect.Field jvm = runtime.getClass().getDeclaredField("jvm");
+            jvm.setAccessible(true);
+//            sun.management.VMManagement mgmt = (sun.management.VMManagement) jvm.get(runtime);
+            Object mgmt = jvm.get(runtime);
+            java.lang.reflect.Method pid_method =  
+                    mgmt.getClass().getDeclaredMethod("getProcessId");
+            pid_method.setAccessible(true);
+
+            return (Integer) pid_method.invoke(mgmt);
+        } catch (Exception e) {
+            throw new PropagatedRuntimeException("Test depends on (fragile) getMyPid method which does not work here", e);
+        }
+    }
+
+    @Test(groups="Integration")
+    public void testRunningPid() {
+        ProcessTaskWrapper<Integer> t = submit(SshEffectorTasks.codePidRunning(getMyPid()));
+        Assert.assertEquals(t.getTask().getUnchecked(), (Integer)0);
+        ProcessTaskWrapper<Boolean> t2 = submit(SshEffectorTasks.isPidRunning(getMyPid()));
+        Assert.assertTrue(t2.getTask().getUnchecked());
+    }
+
+    @Test(groups="Integration")
+    public void testRunningPidFromFile() throws IOException {
+        File f = File.createTempFile("testBrooklynPid", ".pid");
+        Files.write( (""+getMyPid()).getBytes(), f );
+        ProcessTaskWrapper<Integer> t = submit(SshEffectorTasks.codePidFromFileRunning(f.getPath()));
+        Assert.assertEquals(t.getTask().getUnchecked(), (Integer)0);
+        ProcessTaskWrapper<Boolean> t2 = submit(SshEffectorTasks.isPidFromFileRunning(f.getPath()));
+        Assert.assertTrue(t2.getTask().getUnchecked());
+    }
+
+    @Test(groups="Integration")
+    public void testRequirePidFromFileOnFailure() throws IOException {
+        File f = File.createTempFile("testBrooklynPid", ".pid");
+        Files.write( "99999".getBytes(), f );
+        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidFromFileRunning(f.getPath()));
+        
+        setExpectingFailure();
+        try {
+            t.getTask().getUnchecked();
+        } catch (Exception e) {
+            log.info("The error if required PID is not found is: "+e);
+            clearExpectedFailure();
+            Assert.assertTrue(e.toString().contains("Process with PID"), "Expected nice clue in error but got: "+e);
+            Assert.assertEquals(t.getExitCode(), (Integer)1);
+        }
+        checkExpectedFailure();
+    }
+
+    @Test(groups="Integration")
+    public void testRequirePidFromFileOnFailureNoSuchFile() throws IOException {
+        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidFromFileRunning("/path/does/not/exist/SADVQW"));
+        
+        setExpectingFailure();
+        try {
+            t.getTask().getUnchecked();
+        } catch (Exception e) {
+            log.info("The error if required PID is not found is: "+e);
+            clearExpectedFailure();
+            Assert.assertTrue(e.toString().contains("Process with PID"), "Expected nice clue in error but got: "+e);
+            Assert.assertEquals(t.getExitCode(), (Integer)1);
+        }
+        checkExpectedFailure();
+    }
+
+    @Test(groups="Integration")
+    public void testRequirePidFromFileOnFailureTooManyFiles() throws IOException {
+        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidFromFileRunning("/*"));
+        
+        setExpectingFailure();
+        try {
+            t.getTask().getUnchecked();
+        } catch (Exception e) {
+            log.info("The error if required PID is not found is: "+e);
+            clearExpectedFailure();
+            Assert.assertTrue(e.toString().contains("Process with PID"), "Expected nice clue in error but got: "+e);
+            Assert.assertEquals(t.getExitCode(), (Integer)2);
+        }
+        checkExpectedFailure();
+    }
+
+    @Test(groups="Integration")
+    public void testRequirePidFromFileOnSuccess() throws IOException {
+        File f = File.createTempFile("testBrooklynPid", ".pid");
+        Files.write( (""+getMyPid()).getBytes(), f );
+        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidFromFileRunning(f.getPath()));
+        
+        t.getTask().getUnchecked();
+    }
+
+    @Test(groups="Integration")
+    public void testRequirePidFromFileOnSuccessAcceptsWildcards() throws IOException {
+        File f = File.createTempFile("testBrooklynPid", ".pid");
+        Files.write( (""+getMyPid()).getBytes(), f );
+        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidFromFileRunning(f.getPath()+"*"));
+        
+        t.getTask().getUnchecked();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/core/src/test/java/org/apache/brooklyn/util/core/task/ssh/SshEffectorTasksTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/task/ssh/SshEffectorTasksTest.java b/core/src/test/java/org/apache/brooklyn/util/core/task/ssh/SshEffectorTasksTest.java
deleted file mode 100644
index 92f45d7..0000000
--- a/core/src/test/java/org/apache/brooklyn/util/core/task/ssh/SshEffectorTasksTest.java
+++ /dev/null
@@ -1,264 +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.util.core.task.ssh;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Arrays;
-
-import org.apache.brooklyn.api.location.LocationSpec;
-import org.apache.brooklyn.api.mgmt.ManagementContext;
-import org.apache.brooklyn.api.mgmt.TaskAdaptable;
-import org.apache.brooklyn.api.mgmt.TaskFactory;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
-import org.apache.brooklyn.util.core.task.ssh.SshFetchTaskWrapper;
-import org.apache.brooklyn.util.core.task.ssh.SshPutTaskWrapper;
-import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
-import org.apache.brooklyn.util.exceptions.PropagatedRuntimeException;
-import org.apache.brooklyn.util.net.Urls;
-import org.apache.commons.io.FileUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
-import org.apache.brooklyn.location.ssh.SshMachineLocation;
-
-import com.google.common.io.Files;
-
-public class SshEffectorTasksTest {
-
-    private static final Logger log = LoggerFactory.getLogger(SshEffectorTasksTest.class);
-    
-    TestApplication app;
-    ManagementContext mgmt;
-    SshMachineLocation host;
-    File tempDir;
-    
-    boolean failureExpected;
-
-    @BeforeMethod(alwaysRun=true)
-    public void setup() throws Exception {
-        app = TestApplication.Factory.newManagedInstanceForTests();
-        mgmt = app.getManagementContext();
-        
-        LocalhostMachineProvisioningLocation lhc = mgmt.getLocationManager().createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class));
-        host = lhc.obtain();
-        app.start(Arrays.asList(host));
-        clearExpectedFailure();
-        tempDir = Files.createTempDir();
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        if (mgmt != null) Entities.destroyAll(mgmt);
-        mgmt = null;
-        FileUtils.deleteDirectory(tempDir);
-        checkExpectedFailure();
-    }
-
-    protected void checkExpectedFailure() {
-        if (failureExpected) {
-            clearExpectedFailure();
-            Assert.fail("Test should have thrown an exception but it did not.");
-        }
-    }
-    
-    protected void clearExpectedFailure() {
-        failureExpected = false;
-    }
-
-    protected void setExpectingFailure() {
-        failureExpected = true;
-    }
-    
-    public <T extends TaskAdaptable<?>> T submit(final TaskFactory<T> taskFactory) {
-        return Entities.submit(app, taskFactory);
-    }
-    
-    // ------------------- basic ssh
-    
-    @Test(groups="Integration")
-    public void testSshEchoHello() {
-        ProcessTaskWrapper<Integer> t = submit(SshEffectorTasks.ssh("sleep 1 ; echo hello world"));
-        Assert.assertFalse(t.isDone());
-        Assert.assertEquals(t.get(), (Integer)0);
-        Assert.assertEquals(t.getTask().getUnchecked(), (Integer)0);
-        Assert.assertEquals(t.getStdout().trim(), "hello world");
-    }
-
-    @Test(groups="Integration")
-    public void testSshPut() throws IOException {
-        String fn = Urls.mergePaths(tempDir.getPath(), "f1");
-        SshPutTaskWrapper t = submit(SshEffectorTasks.put(fn).contents("hello world"));
-        t.block();
-        Assert.assertEquals(FileUtils.readFileToString(new File(fn)), "hello world");
-        // and make sure this doesn't throw
-        Assert.assertTrue(t.isDone());
-        Assert.assertTrue(t.isSuccessful());
-        Assert.assertEquals(t.get(), null);
-        Assert.assertEquals(t.getExitCode(), (Integer)0);
-    }
-
-    @Test(groups="Integration")
-    public void testSshFetch() throws IOException {
-        String fn = Urls.mergePaths(tempDir.getPath(), "f2");
-        FileUtils.write(new File(fn), "hello fetched world");
-        
-        SshFetchTaskWrapper t = submit(SshEffectorTasks.fetch(fn));
-        t.block();
-        
-        Assert.assertTrue(t.isDone());
-        Assert.assertEquals(t.get(), "hello fetched world");
-    }
-
-    // ----------------- pid stuff
-    
-    @Test(groups="Integration")
-    public void testNonRunningPid() {
-        ProcessTaskWrapper<Integer> t = submit(SshEffectorTasks.codePidRunning(99999));
-        Assert.assertNotEquals(t.getTask().getUnchecked(), (Integer)0);
-        Assert.assertNotEquals(t.getExitCode(), (Integer)0);
-        ProcessTaskWrapper<Boolean> t2 = submit(SshEffectorTasks.isPidRunning(99999));
-        Assert.assertFalse(t2.getTask().getUnchecked());
-    }
-
-    @Test(groups="Integration")
-    public void testNonRunningPidRequired() {
-        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidRunning(99999));
-        setExpectingFailure();
-        try {
-            t.getTask().getUnchecked();
-        } catch (Exception e) {
-            log.info("The error if required PID is not found is: "+e);
-            clearExpectedFailure();
-            Assert.assertTrue(e.toString().contains("Process with PID"), "Expected nice clue in error but got: "+e);
-        }
-        checkExpectedFailure();
-    }
-
-    public static Integer getMyPid() {
-        try {
-            java.lang.management.RuntimeMXBean runtime = 
-                    java.lang.management.ManagementFactory.getRuntimeMXBean();
-            java.lang.reflect.Field jvm = runtime.getClass().getDeclaredField("jvm");
-            jvm.setAccessible(true);
-//            sun.management.VMManagement mgmt = (sun.management.VMManagement) jvm.get(runtime);
-            Object mgmt = jvm.get(runtime);
-            java.lang.reflect.Method pid_method =  
-                    mgmt.getClass().getDeclaredMethod("getProcessId");
-            pid_method.setAccessible(true);
-
-            return (Integer) pid_method.invoke(mgmt);
-        } catch (Exception e) {
-            throw new PropagatedRuntimeException("Test depends on (fragile) getMyPid method which does not work here", e);
-        }
-    }
-
-    @Test(groups="Integration")
-    public void testRunningPid() {
-        ProcessTaskWrapper<Integer> t = submit(SshEffectorTasks.codePidRunning(getMyPid()));
-        Assert.assertEquals(t.getTask().getUnchecked(), (Integer)0);
-        ProcessTaskWrapper<Boolean> t2 = submit(SshEffectorTasks.isPidRunning(getMyPid()));
-        Assert.assertTrue(t2.getTask().getUnchecked());
-    }
-
-    @Test(groups="Integration")
-    public void testRunningPidFromFile() throws IOException {
-        File f = File.createTempFile("testBrooklynPid", ".pid");
-        Files.write( (""+getMyPid()).getBytes(), f );
-        ProcessTaskWrapper<Integer> t = submit(SshEffectorTasks.codePidFromFileRunning(f.getPath()));
-        Assert.assertEquals(t.getTask().getUnchecked(), (Integer)0);
-        ProcessTaskWrapper<Boolean> t2 = submit(SshEffectorTasks.isPidFromFileRunning(f.getPath()));
-        Assert.assertTrue(t2.getTask().getUnchecked());
-    }
-
-    @Test(groups="Integration")
-    public void testRequirePidFromFileOnFailure() throws IOException {
-        File f = File.createTempFile("testBrooklynPid", ".pid");
-        Files.write( "99999".getBytes(), f );
-        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidFromFileRunning(f.getPath()));
-        
-        setExpectingFailure();
-        try {
-            t.getTask().getUnchecked();
-        } catch (Exception e) {
-            log.info("The error if required PID is not found is: "+e);
-            clearExpectedFailure();
-            Assert.assertTrue(e.toString().contains("Process with PID"), "Expected nice clue in error but got: "+e);
-            Assert.assertEquals(t.getExitCode(), (Integer)1);
-        }
-        checkExpectedFailure();
-    }
-
-    @Test(groups="Integration")
-    public void testRequirePidFromFileOnFailureNoSuchFile() throws IOException {
-        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidFromFileRunning("/path/does/not/exist/SADVQW"));
-        
-        setExpectingFailure();
-        try {
-            t.getTask().getUnchecked();
-        } catch (Exception e) {
-            log.info("The error if required PID is not found is: "+e);
-            clearExpectedFailure();
-            Assert.assertTrue(e.toString().contains("Process with PID"), "Expected nice clue in error but got: "+e);
-            Assert.assertEquals(t.getExitCode(), (Integer)1);
-        }
-        checkExpectedFailure();
-    }
-
-    @Test(groups="Integration")
-    public void testRequirePidFromFileOnFailureTooManyFiles() throws IOException {
-        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidFromFileRunning("/*"));
-        
-        setExpectingFailure();
-        try {
-            t.getTask().getUnchecked();
-        } catch (Exception e) {
-            log.info("The error if required PID is not found is: "+e);
-            clearExpectedFailure();
-            Assert.assertTrue(e.toString().contains("Process with PID"), "Expected nice clue in error but got: "+e);
-            Assert.assertEquals(t.getExitCode(), (Integer)2);
-        }
-        checkExpectedFailure();
-    }
-
-    @Test(groups="Integration")
-    public void testRequirePidFromFileOnSuccess() throws IOException {
-        File f = File.createTempFile("testBrooklynPid", ".pid");
-        Files.write( (""+getMyPid()).getBytes(), f );
-        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidFromFileRunning(f.getPath()));
-        
-        t.getTask().getUnchecked();
-    }
-
-    @Test(groups="Integration")
-    public void testRequirePidFromFileOnSuccessAcceptsWildcards() throws IOException {
-        File f = File.createTempFile("testBrooklynPid", ".pid");
-        Files.write( (""+getMyPid()).getBytes(), f );
-        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidFromFileRunning(f.getPath()+"*"));
-        
-        t.getTask().getUnchecked();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/core/src/test/java/org/apache/brooklyn/util/core/task/ssh/SshTasksTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/task/ssh/SshTasksTest.java b/core/src/test/java/org/apache/brooklyn/util/core/task/ssh/SshTasksTest.java
index 3ef139e..6b6c0b1 100644
--- a/core/src/test/java/org/apache/brooklyn/util/core/task/ssh/SshTasksTest.java
+++ b/core/src/test/java/org/apache/brooklyn/util/core/task/ssh/SshTasksTest.java
@@ -26,6 +26,7 @@ import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasksTest;
 import org.apache.commons.io.FileUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/CumulusRDFApplication.java
----------------------------------------------------------------------
diff --git a/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/CumulusRDFApplication.java b/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/CumulusRDFApplication.java
index ef925c6..e7e1df9 100644
--- a/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/CumulusRDFApplication.java
+++ b/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/CumulusRDFApplication.java
@@ -46,6 +46,7 @@ import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.location.PortRanges;
 import org.apache.brooklyn.effector.core.EffectorBody;
 import org.apache.brooklyn.effector.core.Effectors;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.java.UsesJava;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.entity.nosql.cassandra.CassandraDatacenter;
@@ -64,7 +65,6 @@ import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.core.text.TemplateProcessor;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.text.Strings;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/sandbox/extra/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeSaltImpl.java
----------------------------------------------------------------------
diff --git a/sandbox/extra/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeSaltImpl.java b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeSaltImpl.java
index 70747b5..58ec93f 100644
--- a/sandbox/extra/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeSaltImpl.java
+++ b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeSaltImpl.java
@@ -22,7 +22,6 @@ import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.salt.SaltConfig;
 import org.apache.brooklyn.entity.salt.SaltConfigs;
 import org.apache.brooklyn.entity.salt.SaltLifecycleEffectorTasks;
@@ -40,6 +39,7 @@ import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.database.postgresql.PostgreSqlNode;
 import org.apache.brooklyn.effector.core.EffectorBody;
 import org.apache.brooklyn.effector.core.Effectors;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.sensor.core.DependentConfiguration;
 import org.apache.brooklyn.sensor.feed.ssh.SshFeed;
 import org.apache.brooklyn.sensor.feed.ssh.SshPollConfig;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltLifecycleEffectorTasks.java
----------------------------------------------------------------------
diff --git a/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltLifecycleEffectorTasks.java b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltLifecycleEffectorTasks.java
index 4fa3d96..198d139 100644
--- a/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltLifecycleEffectorTasks.java
+++ b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltLifecycleEffectorTasks.java
@@ -23,10 +23,10 @@ import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.server.BrooklynServerConfig;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
 import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltTasks.java
----------------------------------------------------------------------
diff --git a/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltTasks.java b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltTasks.java
index 87096a6..c00e48b 100644
--- a/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltTasks.java
+++ b/sandbox/extra/src/main/java/org/apache/brooklyn/entity/salt/SaltTasks.java
@@ -32,10 +32,10 @@ import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
 import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.core.text.TemplateProcessor;
 
 import org.apache.brooklyn.effector.core.EffectorTasks;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.net.Urls;
 import org.apache.brooklyn.util.ssh.BashCommands;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/sandbox/extra/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSaltLiveTest.java
----------------------------------------------------------------------
diff --git a/sandbox/extra/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSaltLiveTest.java b/sandbox/extra/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSaltLiveTest.java
index 1a42cbb..b25c92f 100644
--- a/sandbox/extra/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSaltLiveTest.java
+++ b/sandbox/extra/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSaltLiveTest.java
@@ -24,7 +24,6 @@ import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.PortRange;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.PortRanges;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.entity.database.postgresql.PostgreSqlNodeSaltImpl;
 import org.apache.brooklyn.entity.salt.SaltConfig;
@@ -40,6 +39,7 @@ import org.apache.brooklyn.entity.database.VogellaExampleAccess;
 import org.apache.brooklyn.entity.database.postgresql.PostgreSqlIntegrationTest;
 import org.apache.brooklyn.entity.database.postgresql.PostgreSqlNode;
 import org.apache.brooklyn.effector.core.EffectorTasks;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.time.Duration;
 
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeSshDriver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeSshDriver.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeSshDriver.java
index f27a6dc..6962767 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeSshDriver.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeSshDriver.java
@@ -31,6 +31,7 @@ import java.util.Map;
 
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.drivers.downloads.DownloadSubstituters;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNode.ExistingFileBehaviour;
 import org.apache.brooklyn.entity.java.JavaSoftwareProcessSshDriver;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
@@ -39,7 +40,6 @@ import org.apache.brooklyn.util.core.file.ArchiveBuilder;
 import org.apache.brooklyn.util.core.file.ArchiveUtils;
 import org.apache.brooklyn.util.core.internal.ssh.SshTool;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.net.Networking;
 import org.apache.brooklyn.util.net.Urls;
 import org.apache.brooklyn.util.os.Os;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/BrooklynNodeUpgradeEffectorBody.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/BrooklynNodeUpgradeEffectorBody.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/BrooklynNodeUpgradeEffectorBody.java
index 0b1c089..b1cb9be 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/BrooklynNodeUpgradeEffectorBody.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/effector/BrooklynNodeUpgradeEffectorBody.java
@@ -34,6 +34,7 @@ import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.EntityTasks;
 import org.apache.brooklyn.effector.core.EffectorBody;
 import org.apache.brooklyn.effector.core.Effectors;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynCluster;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNodeDriver;
@@ -43,7 +44,6 @@ import org.apache.brooklyn.entity.software.base.SoftwareProcess.StopSoftwarePara
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
 import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.net.Urls;
 import org.apache.brooklyn.util.text.Identifiers;
 import org.apache.brooklyn.util.text.Strings;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefLifecycleEffectorTasks.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefLifecycleEffectorTasks.java b/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefLifecycleEffectorTasks.java
index 45c639c..03b7518 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefLifecycleEffectorTasks.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefLifecycleEffectorTasks.java
@@ -26,6 +26,7 @@ import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.location.Machines;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks;
 import org.slf4j.Logger;
@@ -37,7 +38,6 @@ import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
 import org.apache.brooklyn.util.core.task.TaskTags;
 import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.net.Urls;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefSoloTasks.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefSoloTasks.java b/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefSoloTasks.java
index c543779..327b70b 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefSoloTasks.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefSoloTasks.java
@@ -21,7 +21,7 @@ package org.apache.brooklyn.entity.chef;
 import java.util.Map;
 
 import org.apache.brooklyn.api.mgmt.TaskFactory;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.ssh.BashCommands;
 
 import com.google.common.annotations.Beta;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefTasks.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefTasks.java b/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefTasks.java
index a7b79a3..c8a8b39 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefTasks.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/chef/ChefTasks.java
@@ -24,13 +24,13 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.mgmt.TaskAdaptable;
 import org.apache.brooklyn.api.mgmt.TaskFactory;
 import org.apache.brooklyn.effector.core.EffectorTasks;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.file.ArchiveTasks;
 import org.apache.brooklyn.util.core.file.ArchiveUtils.ArchiveType;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
 import org.apache.brooklyn.util.core.task.TaskBuilder;
 import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.net.Urls;
 import org.apache.brooklyn.util.ssh.BashCommands;
 import org.apache.brooklyn.util.text.Identifiers;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/base/src/main/java/org/apache/brooklyn/entity/java/JavaSoftwareProcessSshDriver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/java/JavaSoftwareProcessSshDriver.java b/software/base/src/main/java/org/apache/brooklyn/entity/java/JavaSoftwareProcessSshDriver.java
index 6e4b7c7..ce5f82d 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/java/JavaSoftwareProcessSshDriver.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/java/JavaSoftwareProcessSshDriver.java
@@ -32,6 +32,7 @@ import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.effector.core.EffectorTasks;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.software.base.AbstractSoftwareProcessSshDriver;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -54,7 +55,6 @@ import org.apache.brooklyn.util.core.flags.TypeCoercions;
 import org.apache.brooklyn.util.core.internal.ssh.ShellTool;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
 import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.core.task.ssh.SshTasks;
 import org.apache.brooklyn.util.core.task.system.ProcessTaskFactory;
 import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineEntityImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineEntityImpl.java b/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineEntityImpl.java
index 144894b..1bb994d 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineEntityImpl.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/machine/MachineEntityImpl.java
@@ -24,6 +24,7 @@ import java.util.concurrent.TimeoutException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.core.location.Machines;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.software.base.AbstractSoftwareProcessSshDriver;
 import org.apache.brooklyn.entity.software.base.EmptySoftwareProcessDriver;
 import org.apache.brooklyn.entity.software.base.EmptySoftwareProcessImpl;
@@ -32,7 +33,6 @@ import org.apache.brooklyn.sensor.feed.ssh.SshFeed;
 import org.apache.brooklyn.sensor.feed.ssh.SshPollConfig;
 import org.apache.brooklyn.sensor.feed.ssh.SshPollValue;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.text.Strings;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessSshDriver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessSshDriver.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessSshDriver.java
index 2be96b6..a303f85 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessSshDriver.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/AbstractSoftwareProcessSshDriver.java
@@ -35,6 +35,7 @@ import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
 import org.apache.brooklyn.effector.core.EffectorTasks;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.software.base.lifecycle.NaiveScriptRunner;
 import org.apache.brooklyn.entity.software.base.lifecycle.ScriptHelper;
 import org.slf4j.Logger;
@@ -53,7 +54,6 @@ import org.apache.brooklyn.util.core.internal.ssh.SshTool;
 import org.apache.brooklyn.util.core.internal.ssh.sshj.SshjTool;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
 import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
index c2e4cc8..0515166 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java
@@ -55,6 +55,7 @@ import org.apache.brooklyn.core.location.cloud.CloudLocationConfig;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
 import org.apache.brooklyn.effector.core.EffectorBody;
 import org.apache.brooklyn.effector.core.Effectors;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.machine.MachineInitTasks;
 import org.apache.brooklyn.entity.machine.ProvidesProvisioningFlags;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
@@ -80,7 +81,6 @@ import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
 import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandEffector.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandEffector.java b/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandEffector.java
index f91be61..da4a9ce 100644
--- a/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandEffector.java
+++ b/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandEffector.java
@@ -28,11 +28,11 @@ import org.apache.brooklyn.effector.core.AddEffector;
 import org.apache.brooklyn.effector.core.EffectorBody;
 import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.effector.core.Effectors.EffectorBuilder;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks.SshEffectorTaskFactory;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks.SshEffectorTaskFactory;
 import org.apache.brooklyn.util.text.Strings;
 
 import com.google.common.base.Preconditions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverMySqlEntityLiveTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverMySqlEntityLiveTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverMySqlEntityLiveTest.java
index 0166d94..8de4bb0 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverMySqlEntityLiveTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverMySqlEntityLiveTest.java
@@ -21,8 +21,8 @@ package org.apache.brooklyn.entity.chef.mysql;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
 import org.testng.annotations.Test;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverToyMySqlEntity.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverToyMySqlEntity.java b/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverToyMySqlEntity.java
index 468b95e..21d1d2f 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverToyMySqlEntity.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverToyMySqlEntity.java
@@ -22,6 +22,7 @@ import org.apache.brooklyn.api.mgmt.TaskAdaptable;
 import org.apache.brooklyn.api.mgmt.TaskFactory;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.chef.ChefConfig;
 import org.apache.brooklyn.entity.chef.ChefConfigs;
 import org.apache.brooklyn.entity.chef.ChefSoloDriver;
@@ -29,7 +30,6 @@ import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
 import org.apache.brooklyn.sensor.feed.ssh.SshFeed;
 import org.apache.brooklyn.sensor.feed.ssh.SshPollConfig;
 import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.time.Duration;
 
 @Deprecated /** @deprecated since 0.7.0 use see examples {Dynamic,Typed}ToyMySqlEntityChef */

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareEffectorTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareEffectorTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareEffectorTest.java
index 1057ef9..244adf8 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareEffectorTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareEffectorTest.java
@@ -27,9 +27,9 @@ import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.effector.core.Effectors;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks.SshEffectorBody;
 import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks.SshEffectorBody;
 import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;



[23/36] incubator-brooklyn git commit: Rename o.a.b.sensor.feed to o.a.b.feed and o.a.b.core.feed

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeed.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeed.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeed.java
deleted file mode 100644
index e9767d9..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeed.java
+++ /dev/null
@@ -1,412 +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.feed.windows;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import io.cloudsoft.winrm4j.winrm.WinRmToolResponse;
-
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.TimeUnit;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.mgmt.ExecutionContext;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.effector.EffectorTasks;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.core.sensor.Sensors;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
-import org.apache.brooklyn.sensor.feed.AbstractFeed;
-import org.apache.brooklyn.sensor.feed.PollHandler;
-import org.apache.brooklyn.sensor.feed.Poller;
-import org.apache.brooklyn.util.core.flags.TypeCoercions;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.time.Duration;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import com.google.common.reflect.TypeToken;
-
-/**
- * A sensor feed that retrieves performance counters from a Windows host and posts the values to sensors.
- *
- * <p>To use this feed, you must provide the entity, and a collection of mappings between Windows performance counter
- * names and Brooklyn attribute sensors.</p>
- *
- * <p>This feed uses SSH to invoke the windows utility <tt>typeperf</tt> to query for a specific set of performance
- * counters, by name. The values are extracted from the response, and published to the entity's sensors.</p>
- *
- * <p>Example:</p>
- *
- * {@code
- * @Override
- * protected void connectSensors() {
- *     WindowsPerformanceCounterFeed feed = WindowsPerformanceCounterFeed.builder()
- *         .entity(entity)
- *         .addSensor("\\Processor(_total)\\% Idle Time", CPU_IDLE_TIME)
- *         .addSensor("\\Memory\\Available MBytes", AVAILABLE_MEMORY)
- *         .build();
- * }
- * }
- *
- * @since 0.6.0
- * @author richardcloudsoft
- */
-public class WindowsPerformanceCounterFeed extends AbstractFeed {
-
-    private static final Logger log = LoggerFactory.getLogger(WindowsPerformanceCounterFeed.class);
-
-    // This pattern matches CSV line(s) with the date in the first field, and at least one further field.
-    protected static final Pattern lineWithPerfData = Pattern.compile("^\"[\\d:/\\-. ]+\",\".*\"$", Pattern.MULTILINE);
-    private static final Joiner JOINER_ON_SPACE = Joiner.on(' ');
-    private static final Joiner JOINER_ON_COMMA = Joiner.on(',');
-    private static final int OUTPUT_COLUMN_WIDTH = 100;
-
-    @SuppressWarnings("serial")
-    public static final ConfigKey<Collection<WindowsPerformanceCounterPollConfig<?>>> POLLS = ConfigKeys.newConfigKey(
-            new TypeToken<Collection<WindowsPerformanceCounterPollConfig<?>>>() {},
-            "polls");
-
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    public static class Builder {
-        private EntityLocal entity;
-        private Set<WindowsPerformanceCounterPollConfig<?>> polls = Sets.newLinkedHashSet();
-        private Duration period = Duration.of(30, TimeUnit.SECONDS);
-        private String uniqueTag;
-        private volatile boolean built;
-
-        public Builder entity(EntityLocal val) {
-            this.entity = checkNotNull(val, "entity");
-            return this;
-        }
-        public Builder addSensor(WindowsPerformanceCounterPollConfig<?> config) {
-            polls.add(config);
-            return this;
-        }
-        public Builder addSensor(String performanceCounterName, AttributeSensor<?> sensor) {
-            return addSensor(new WindowsPerformanceCounterPollConfig(sensor).performanceCounterName(checkNotNull(performanceCounterName, "performanceCounterName")));
-        }
-        public Builder addSensors(Map<String, AttributeSensor> sensors) {
-            for (Map.Entry<String, AttributeSensor> entry : sensors.entrySet()) {
-                addSensor(entry.getKey(), entry.getValue());
-            }
-            return this;
-        }
-        public Builder period(Duration period) {
-            this.period = checkNotNull(period, "period");
-            return this;
-        }
-        public Builder period(long millis) {
-            return period(millis, TimeUnit.MILLISECONDS);
-        }
-        public Builder period(long val, TimeUnit units) {
-            return period(Duration.of(val, units));
-        }
-        public Builder uniqueTag(String uniqueTag) {
-            this.uniqueTag = uniqueTag;
-            return this;
-        }
-        public WindowsPerformanceCounterFeed build() {
-            built = true;
-            WindowsPerformanceCounterFeed result = new WindowsPerformanceCounterFeed(this);
-            result.setEntity(checkNotNull(entity, "entity"));
-            result.start();
-            return result;
-        }
-        @Override
-        protected void finalize() {
-            if (!built) log.warn("WindowsPerformanceCounterFeed.Builder created, but build() never called");
-        }
-    }
-
-    /**
-     * For rebind; do not call directly; use builder
-     */
-    public WindowsPerformanceCounterFeed() {
-    }
-
-    protected WindowsPerformanceCounterFeed(Builder builder) {
-        List<WindowsPerformanceCounterPollConfig<?>> polls = Lists.newArrayList();
-        for (WindowsPerformanceCounterPollConfig<?> config : builder.polls) {
-            if (!config.isEnabled()) continue;
-            @SuppressWarnings({ "unchecked", "rawtypes" })
-            WindowsPerformanceCounterPollConfig<?> configCopy = new WindowsPerformanceCounterPollConfig(config);
-            if (configCopy.getPeriod() < 0) configCopy.period(builder.period);
-            polls.add(configCopy);
-        }
-        config().set(POLLS, polls);
-        initUniqueTag(builder.uniqueTag, polls);
-    }
-
-    @Override
-    protected void preStart() {
-        Collection<WindowsPerformanceCounterPollConfig<?>> polls = getConfig(POLLS);
-        
-        long minPeriod = Integer.MAX_VALUE;
-        List<String> performanceCounterNames = Lists.newArrayList();
-        for (WindowsPerformanceCounterPollConfig<?> config : polls) {
-            minPeriod = Math.min(minPeriod, config.getPeriod());
-            performanceCounterNames.add(config.getPerformanceCounterName());
-        }
-        
-        Iterable<String> allParams = ImmutableList.<String>builder()
-                .add("(Get-Counter")
-                .add("-Counter")
-                .add(JOINER_ON_COMMA.join(Iterables.transform(performanceCounterNames, QuoteStringFunction.INSTANCE)))
-                .add("-SampleInterval")
-                .add("2") // TODO: extract SampleInterval as a config key
-                .add(").CounterSamples")
-                .add("|")
-                .add("Format-Table")
-                .add(String.format("@{Expression={$_.Path};width=%d},@{Expression={$_.CookedValue};width=%<d}", OUTPUT_COLUMN_WIDTH))
-                .add("-HideTableHeaders")
-                .add("|")
-                .add("Out-String")
-                .add("-Width")
-                .add(String.valueOf(OUTPUT_COLUMN_WIDTH * 2))
-                .build();
-        String command = JOINER_ON_SPACE.join(allParams);
-        log.debug("Windows performance counter poll command for {} will be: {}", entity, command);
-
-        GetPerformanceCountersJob<WinRmToolResponse> job = new GetPerformanceCountersJob(getEntity(), command);
-        getPoller().scheduleAtFixedRate(
-                new CallInEntityExecutionContext(entity, job),
-                new SendPerfCountersToSensors(getEntity(), polls),
-                minPeriod);
-    }
-
-    private static class GetPerformanceCountersJob<T> implements Callable<T> {
-
-        private final Entity entity;
-        private final String command;
-
-        GetPerformanceCountersJob(Entity entity, String command) {
-            this.entity = entity;
-            this.command = command;
-        }
-
-        @Override
-        public T call() throws Exception {
-            WinRmMachineLocation machine = EffectorTasks.getWinRmMachine(entity);
-            WinRmToolResponse response = machine.executePsScript(command);
-            return (T)response;
-        }
-    }
-
-    @SuppressWarnings("unchecked")
-    protected Poller<WinRmToolResponse> getPoller() {
-        return (Poller<WinRmToolResponse>) super.getPoller();
-    }
-
-    /**
-     * A {@link java.util.concurrent.Callable} that wraps another {@link java.util.concurrent.Callable}, where the
-     * inner {@link java.util.concurrent.Callable} is executed in the context of a
-     * specific entity.
-     *
-     * @param <T> The type of the {@link java.util.concurrent.Callable}.
-     */
-    private static class CallInEntityExecutionContext<T> implements Callable<T> {
-        private final Callable<T> job;
-        private EntityLocal entity;
-
-        private CallInEntityExecutionContext(EntityLocal entity, Callable<T> job) {
-            this.job = job;
-            this.entity = entity;
-        }
-
-        @Override
-        public T call() throws Exception {
-            ExecutionContext executionContext = ((EntityInternal) entity).getManagementSupport().getExecutionContext();
-            return executionContext.submit(Maps.newHashMap(), job).get();
-        }
-    }
-
-    @VisibleForTesting
-    static class SendPerfCountersToSensors implements PollHandler<WinRmToolResponse> {
-        private final EntityLocal entity;
-        private final List<WindowsPerformanceCounterPollConfig<?>> polls;
-        private final Set<AttributeSensor<?>> failedAttributes = Sets.newLinkedHashSet();
-        private static final Pattern MACHINE_NAME_LOOKBACK_PATTERN = Pattern.compile(String.format("(?<=\\\\\\\\.{0,%d})\\\\.*", OUTPUT_COLUMN_WIDTH));
-        
-        public SendPerfCountersToSensors(EntityLocal entity, Collection<WindowsPerformanceCounterPollConfig<?>> polls) {
-            this.entity = entity;
-            this.polls = ImmutableList.copyOf(polls);
-        }
-
-        @Override
-        public boolean checkSuccess(WinRmToolResponse val) {
-            // TODO not just using statusCode; also looking at absence of stderr.
-            // Status code is (empirically) unreliable: it returns 0 sometimes even when failed 
-            // (but never returns non-zero on success).
-            if (val.getStatusCode() != 0) return false;
-            String stderr = val.getStdErr();
-            if (stderr == null || stderr.length() != 0) return false;
-            String out = val.getStdOut();
-            if (out == null || out.length() == 0) return false;
-            return true;
-        }
-
-        @Override
-        public void onSuccess(WinRmToolResponse val) {
-            for (String pollResponse : val.getStdOut().split("\r\n")) {
-                if (Strings.isNullOrEmpty(pollResponse)) {
-                    continue;
-                }
-                String path = pollResponse.substring(0, OUTPUT_COLUMN_WIDTH - 1);
-                // The performance counter output prepends the sensor name with "\\<machinename>" so we need to remove it
-                Matcher machineNameLookbackMatcher = MACHINE_NAME_LOOKBACK_PATTERN.matcher(path);
-                if (!machineNameLookbackMatcher.find()) {
-                    continue;
-                }
-                String name = machineNameLookbackMatcher.group(0).trim();
-                String rawValue = pollResponse.substring(OUTPUT_COLUMN_WIDTH).replaceAll("^\\s+", "");
-                WindowsPerformanceCounterPollConfig<?> config = getPollConfig(name);
-                Class<?> clazz = config.getSensor().getType();
-                AttributeSensor<Object> attribute = (AttributeSensor<Object>) Sensors.newSensor(clazz, config.getSensor().getName(), config.getDescription());
-                try {
-                    Object value = TypeCoercions.coerce(rawValue, TypeToken.of(clazz));
-                    entity.setAttribute(attribute, value);
-                } catch (Exception e) {
-                    Exceptions.propagateIfFatal(e);
-                    if (failedAttributes.add(attribute)) {
-                        log.warn("Failed to coerce value '{}' to {} for {} -> {}", new Object[] {rawValue, clazz, entity, attribute});
-                    } else {
-                        if (log.isTraceEnabled()) log.trace("Failed (repeatedly) to coerce value '{}' to {} for {} -> {}", new Object[] {rawValue, clazz, entity, attribute});
-                    }
-                }
-            }
-        }
-
-        @Override
-        public void onFailure(WinRmToolResponse val) {
-            log.error("Windows Performance Counter query did not respond as expected. exitcode={} stdout={} stderr={}",
-                    new Object[]{val.getStatusCode(), val.getStdOut(), val.getStdErr()});
-            for (WindowsPerformanceCounterPollConfig<?> config : polls) {
-                Class<?> clazz = config.getSensor().getType();
-                AttributeSensor<?> attribute = Sensors.newSensor(clazz, config.getSensor().getName(), config.getDescription());
-                entity.setAttribute(attribute, null);
-            }
-        }
-
-        @Override
-        public void onException(Exception exception) {
-            log.error("Detected exception while retrieving Windows Performance Counters from entity " +
-                    entity.getDisplayName(), exception);
-            for (WindowsPerformanceCounterPollConfig<?> config : polls) {
-                entity.setAttribute(Sensors.newSensor(config.getSensor().getClass(), config.getPerformanceCounterName(), config.getDescription()), null);
-            }
-        }
-
-        @Override
-        public String getDescription() {
-            return "" + polls;
-        }
-
-        @Override
-        public String toString() {
-            return super.toString()+"["+getDescription()+"]";
-        }
-
-        private WindowsPerformanceCounterPollConfig<?> getPollConfig(String sensorName) {
-            for (WindowsPerformanceCounterPollConfig<?> poll : polls) {
-                if (poll.getPerformanceCounterName().equalsIgnoreCase(sensorName)) {
-                    return poll;
-                }
-            }
-            throw new IllegalStateException(String.format("%s not found in configured polls: %s", sensorName, polls));
-        }
-    }
-
-    static class PerfCounterValueIterator implements Iterator<String> {
-
-        // This pattern matches the contents of the first field, and optionally matches the rest of the line as
-        // further fields. Feed the second match back into the pattern again to get the next field, and repeat until
-        // all fields are discovered.
-        protected static final Pattern splitPerfData = Pattern.compile("^\"([^\\\"]*)\"((,\"[^\\\"]*\")*)$");
-
-        private Matcher matcher;
-
-        public PerfCounterValueIterator(String input) {
-            matcher = splitPerfData.matcher(input);
-            // Throw away the first element (the timestamp) (and also confirm that we have a pattern match)
-            checkArgument(hasNext(), "input "+input+" does not match expected pattern "+splitPerfData.pattern());
-            next();
-        }
-
-        @Override
-        public boolean hasNext() {
-            return matcher != null && matcher.find();
-        }
-
-        @Override
-        public String next() {
-            String next = matcher.group(1);
-
-            String remainder = matcher.group(2);
-            if (!Strings.isNullOrEmpty(remainder)) {
-                assert remainder.startsWith(",");
-                remainder = remainder.substring(1);
-                matcher = splitPerfData.matcher(remainder);
-            } else {
-                matcher = null;
-            }
-
-            return next;
-        }
-
-        @Override
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
-    }
-
-    private static enum QuoteStringFunction implements Function<String, String> {
-        INSTANCE;
-
-        @Nullable
-        @Override
-        public String apply(@Nullable String input) {
-            return input != null ? "\"" + input + "\"" : null;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterPollConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterPollConfig.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterPollConfig.java
deleted file mode 100644
index 34bc08c..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterPollConfig.java
+++ /dev/null
@@ -1,53 +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.feed.windows;
-
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.sensor.feed.PollConfig;
-
-import com.google.common.base.Function;
-import com.google.common.base.Functions;
-
-public class WindowsPerformanceCounterPollConfig<T> extends PollConfig<Object, T, WindowsPerformanceCounterPollConfig<T>>{
-
-    private String performanceCounterName;
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    public WindowsPerformanceCounterPollConfig(AttributeSensor<T> sensor) {
-        super(sensor);
-        description(sensor.getDescription());
-        onSuccess((Function)Functions.identity());
-    }
-
-    public WindowsPerformanceCounterPollConfig(WindowsPerformanceCounterPollConfig<T> other) {
-        super(other);
-        this.performanceCounterName = other.performanceCounterName;
-    }
-
-    public String getPerformanceCounterName() {
-        return performanceCounterName;
-    }
-    
-    public WindowsPerformanceCounterPollConfig<T> performanceCounterName(String val) {
-        this.performanceCounterName = val; return this;
-    }
-
-    @Override protected String toStringPollSource() { return performanceCounterName; }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/main/java/org/apache/brooklyn/util/core/http/HttpToolResponse.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/http/HttpToolResponse.java b/core/src/main/java/org/apache/brooklyn/util/core/http/HttpToolResponse.java
index 9e8e061..ad768f7 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/http/HttpToolResponse.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/http/HttpToolResponse.java
@@ -26,7 +26,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.brooklyn.sensor.feed.http.HttpPollValue;
+import org.apache.brooklyn.feed.http.HttpPollValue;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.stream.Streams;
 import org.apache.brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/core/feed/ConfigToAttributesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/feed/ConfigToAttributesTest.java b/core/src/test/java/org/apache/brooklyn/core/feed/ConfigToAttributesTest.java
new file mode 100644
index 0000000..1cc48df
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/feed/ConfigToAttributesTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.core.feed;
+
+import static org.testng.Assert.assertEquals;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.feed.ConfigToAttributes;
+import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
+import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.TemplatedStringAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class ConfigToAttributesTest {
+
+    private ManagementContextInternal managementContext;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        managementContext = new LocalManagementContext();
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (managementContext != null) Entities.destroyAll(managementContext);
+    }
+    
+    @Test
+    public void testApplyTemplatedConfigWithEntity() {
+        TestApplication app = managementContext.getEntityManager().createEntity(EntitySpec.create(TestApplication.class)
+                .configure(TestEntity.CONF_NAME, "myval"));
+        Entities.startManagement(app, managementContext);
+        
+        BasicAttributeSensorAndConfigKey<String> key = new TemplatedStringAttributeSensorAndConfigKey("mykey", "my descr", "${config['test.confName']!'notfound'}");
+        String val = ConfigToAttributes.apply(app, key);
+        assertEquals(app.getAttribute(key), val);
+        assertEquals(val, "myval");
+
+    }
+    
+    @Test
+    public void testApplyTemplatedConfigWithManagementContext() {
+        managementContext.getBrooklynProperties().put(TestEntity.CONF_NAME, "myglobalval");
+        BasicAttributeSensorAndConfigKey<String> key = new TemplatedStringAttributeSensorAndConfigKey("mykey", "my descr", "${config['test.confName']!'notfound'}");
+        String val = ConfigToAttributes.transform(managementContext, key);
+        assertEquals(val, "myglobalval");
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/core/feed/PollerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/feed/PollerTest.java b/core/src/test/java/org/apache/brooklyn/core/feed/PollerTest.java
new file mode 100644
index 0000000..0f2c1ce
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/feed/PollerTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.core.feed;
+
+import static org.testng.Assert.assertTrue;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.feed.PollHandler;
+import org.apache.brooklyn.core.feed.Poller;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.task.DynamicTasks;
+import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class PollerTest extends BrooklynAppUnitTestSupport {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PollerTest.class);
+
+    private TestEntity entity;
+    private Poller<Integer> poller;
+    
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        poller = new Poller<Integer>(entity, false);
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    @Override
+    public void tearDown() throws Exception {
+        if (poller != null) poller.stop();
+        super.tearDown();
+    }
+    
+    @Test(groups={"Integration", "WIP"}) // because takes > 1 second
+    public void testPollingSubTaskFailsOnceKeepsGoing() throws Exception {
+        final AtomicInteger counter = new AtomicInteger();
+        poller.scheduleAtFixedRate(
+                new Callable<Integer>() {
+                    @Override public Integer call() throws Exception {
+                        int result = counter.incrementAndGet();
+                        if (result % 2 == 0) {
+                            DynamicTasks.queue("in-poll", new Runnable() {
+                                public void run() {
+                                    throw new IllegalStateException("Simulating error in sub-task for poll");
+                                }});
+                        }
+                        return result;
+                    }
+                },
+                new PollHandler<Integer>() {
+                    @Override public boolean checkSuccess(Integer val) {
+                        return true;
+                    }
+                    @Override public void onSuccess(Integer val) {
+                        
+                    }
+                    @Override public void onFailure(Integer val) {
+                    }
+                    @Override
+                    public void onException(Exception exception) {
+                        LOG.info("Exception in test poller", exception);
+                    }
+                    @Override public String getDescription() {
+                        return "mypollhandler";
+                    }
+                }, 
+                new Duration(10, TimeUnit.MILLISECONDS));
+        poller.start();
+        
+        Asserts.succeedsContinually(MutableMap.of("timeout", 2*1000, "period", 500), new Runnable() {
+            int oldCounter = -1;
+            @Override public void run() {
+                assertTrue(counter.get() > oldCounter);
+                oldCounter = counter.get();
+            }
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/core/location/TestPortSupplierLocation.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/location/TestPortSupplierLocation.java b/core/src/test/java/org/apache/brooklyn/core/location/TestPortSupplierLocation.java
index a5b4294..b8d8c35 100644
--- a/core/src/test/java/org/apache/brooklyn/core/location/TestPortSupplierLocation.java
+++ b/core/src/test/java/org/apache/brooklyn/core/location/TestPortSupplierLocation.java
@@ -21,11 +21,11 @@ package org.apache.brooklyn.core.location;
 import static org.testng.Assert.assertEquals;
 
 import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.feed.ConfigToAttributes;
 import org.apache.brooklyn.core.location.PortRanges;
 import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFeedTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFeedTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFeedTest.java
index f0c6551..4a724e4 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFeedTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFeedTest.java
@@ -35,14 +35,14 @@ import org.apache.brooklyn.core.mgmt.internal.BrooklynGarbageCollector;
 import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.core.test.entity.TestEntityImpl.TestEntityWithoutEnrichers;
-import org.apache.brooklyn.sensor.feed.function.FunctionFeed;
-import org.apache.brooklyn.sensor.feed.function.FunctionPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
-import org.apache.brooklyn.sensor.feed.ssh.SshFeed;
-import org.apache.brooklyn.sensor.feed.ssh.SshPollConfig;
-import org.apache.brooklyn.sensor.feed.ssh.SshValueFunctions;
+import org.apache.brooklyn.feed.function.FunctionFeed;
+import org.apache.brooklyn.feed.function.FunctionPollConfig;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
+import org.apache.brooklyn.feed.ssh.SshFeed;
+import org.apache.brooklyn.feed.ssh.SshPollConfig;
+import org.apache.brooklyn.feed.ssh.SshValueFunctions;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.collections.MutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/feed/function/FunctionFeedTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/feed/function/FunctionFeedTest.java b/core/src/test/java/org/apache/brooklyn/feed/function/FunctionFeedTest.java
new file mode 100644
index 0000000..c362e4e6
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/feed/function/FunctionFeedTest.java
@@ -0,0 +1,315 @@
+/*
+ * 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.feed.function;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.Feed;
+import org.apache.brooklyn.api.sensor.SensorEvent;
+import org.apache.brooklyn.api.sensor.SensorEventListener;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.entity.EntityInternal.FeedSupport;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.feed.function.FunctionFeed;
+import org.apache.brooklyn.feed.function.FunctionFeedTest;
+import org.apache.brooklyn.feed.function.FunctionPollConfig;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.base.Predicates;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.Callables;
+
+public class FunctionFeedTest extends BrooklynAppUnitTestSupport {
+
+    private static final Logger log = LoggerFactory.getLogger(FunctionFeedTest.class);
+    
+    final static AttributeSensor<String> SENSOR_STRING = Sensors.newStringSensor("aString", "");
+    final static AttributeSensor<Integer> SENSOR_INT = Sensors.newIntegerSensor("aLong", "");
+
+    private Location loc;
+    private EntityLocal entity;
+    private FunctionFeed feed;
+    
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        loc = new LocalhostMachineProvisioningLocation();
+        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        app.start(ImmutableList.of(loc));
+    }
+
+    @AfterMethod(alwaysRun=true)
+    @Override
+    public void tearDown() throws Exception {
+        if (feed != null) feed.stop();
+        super.tearDown();
+    }
+    
+    @Test
+    public void testPollsFunctionRepeatedlyToSetAttribute() throws Exception {
+        feed = FunctionFeed.builder()
+                .entity(entity)
+                .poll(new FunctionPollConfig<Integer,Integer>(SENSOR_INT)
+                        .period(1)
+                        .callable(new IncrementingCallable())
+                        //.onSuccess((Function<Object,Integer>)(Function)Functions.identity()))
+                        )
+                .build();
+        
+        Asserts.succeedsEventually(new Runnable() {
+            @Override
+            public void run() {
+                Integer val = entity.getAttribute(SENSOR_INT);
+                assertTrue(val != null && val > 2, "val=" + val);
+            }
+        });
+    }
+    
+    @Test
+    public void testFeedDeDupe() throws Exception {
+        testPollsFunctionRepeatedlyToSetAttribute();
+        entity.addFeed(feed);
+        log.info("Feed 0 is: "+feed);
+        Feed feed0 = feed;
+        
+        testPollsFunctionRepeatedlyToSetAttribute();
+        entity.addFeed(feed);
+        log.info("Feed 1 is: "+feed);
+        Feed feed1 = feed;
+        Assert.assertFalse(feed1==feed0);
+
+        FeedSupport feeds = ((EntityInternal)entity).feeds();
+        Assert.assertEquals(feeds.getFeeds().size(), 1, "Wrong feed count: "+feeds.getFeeds());
+
+        // a couple extra checks, compared to the de-dupe test in other *FeedTest classes
+        Feed feedAdded = Iterables.getOnlyElement(feeds.getFeeds());
+        Assert.assertTrue(feedAdded==feed1);
+        Assert.assertFalse(feedAdded==feed0);
+    }
+    
+    @Test
+    public void testFeedDeDupeIgnoresSameObject() throws Exception {
+        testPollsFunctionRepeatedlyToSetAttribute();
+        entity.addFeed(feed);
+        assertFeedIsPolling();
+        entity.addFeed(feed);
+        assertFeedIsPollingContinuously();
+    }
+
+    @Test
+    public void testCallsOnSuccessWithResultOfCallable() throws Exception {
+        feed = FunctionFeed.builder()
+                .entity(entity)
+                .poll(new FunctionPollConfig<Integer, Integer>(SENSOR_INT)
+                        .period(1)
+                        .callable(Callables.returning(123))
+                        .onSuccess(new AddOneFunction()))
+                .build();
+
+        EntityTestUtils.assertAttributeEqualsEventually(entity, SENSOR_INT, 124);
+    }
+    
+    @Test
+    public void testCallsOnExceptionWithExceptionFromCallable() throws Exception {
+        final String errMsg = "my err msg";
+        
+        feed = FunctionFeed.builder()
+                .entity(entity)
+                .poll(new FunctionPollConfig<Object, String>(SENSOR_STRING)
+                        .period(1)
+                        .callable(new ExceptionCallable(errMsg))
+                        .onException(new ToStringFunction()))
+                .build();
+
+        Asserts.succeedsEventually(new Runnable() {
+            @Override
+            public void run() {
+                String val = entity.getAttribute(SENSOR_STRING);
+                assertTrue(val != null && val.contains(errMsg), "val=" + val);
+            }
+        });
+    }
+
+    @Test
+    public void testCallsOnFailureWithResultOfCallable() throws Exception {
+        feed = FunctionFeed.builder()
+                .entity(entity)
+                .poll(new FunctionPollConfig<Integer, Integer>(SENSOR_INT)
+                        .period(1)
+                        .callable(Callables.returning(1))
+                        .checkSuccess(Predicates.alwaysFalse())
+                        .onSuccess(new AddOneFunction())
+                        .onFailure(Functions.constant(-1)))
+                .build();
+
+        EntityTestUtils.assertAttributeEqualsEventually(entity, SENSOR_INT, -1);
+    }
+
+    @Test
+    public void testCallsOnExceptionWhenCheckSuccessIsFalseButNoFailureHandler() throws Exception {
+        feed = FunctionFeed.builder()
+                .entity(entity)
+                .poll(new FunctionPollConfig<Integer, Integer>(SENSOR_INT)
+                        .period(1)
+                        .callable(Callables.returning(1))
+                        .checkSuccess(Predicates.alwaysFalse())
+                        .onSuccess(new AddOneFunction())
+                        .onException(Functions.constant(-1)))
+                .build();
+
+        EntityTestUtils.assertAttributeEqualsEventually(entity, SENSOR_INT, -1);
+    }
+    
+    @Test
+    public void testSharesFunctionWhenMultiplePostProcessors() throws Exception {
+        final IncrementingCallable incrementingCallable = new IncrementingCallable();
+        final List<Integer> ints = new CopyOnWriteArrayList<Integer>();
+        final List<String> strings = new CopyOnWriteArrayList<String>();
+        
+        entity.subscribe(entity, SENSOR_INT, new SensorEventListener<Integer>() {
+                @Override public void onEvent(SensorEvent<Integer> event) {
+                    ints.add(event.getValue());
+                }});
+        entity.subscribe(entity, SENSOR_STRING, new SensorEventListener<String>() {
+                @Override public void onEvent(SensorEvent<String> event) {
+                    strings.add(event.getValue());
+                }});
+        
+        feed = FunctionFeed.builder()
+                .entity(entity)
+                .poll(new FunctionPollConfig<Integer, Integer>(SENSOR_INT)
+                        .period(10)
+                        .callable(incrementingCallable))
+                .poll(new FunctionPollConfig<Integer, String>(SENSOR_STRING)
+                        .period(10)
+                        .callable(incrementingCallable)
+                        .onSuccess(new ToStringFunction()))
+                .build();
+
+        Asserts.succeedsEventually(new Runnable() {
+            @Override
+            public void run() {
+                assertEquals(ints.subList(0, 2), ImmutableList.of(0, 1));
+                assertTrue(strings.size()>=2, "wrong strings list: "+strings);
+                assertEquals(strings.subList(0, 2), ImmutableList.of("0", "1"), "wrong strings list: "+strings);
+            }});
+    }
+    
+    @Test
+    @SuppressWarnings("unused")
+    public void testFunctionPollConfigBuilding() throws Exception {
+        FunctionPollConfig<Integer, Integer> typeFromCallable = FunctionPollConfig.forSensor(SENSOR_INT)
+                .period(1)
+                .callable(Callables.returning(1))
+                .onSuccess(Functions.constant(-1));
+
+        FunctionPollConfig<Integer, Integer> typeFromSupplier = FunctionPollConfig.forSensor(SENSOR_INT)
+                .period(1)
+                .supplier(Suppliers.ofInstance(1))
+                .onSuccess(Functions.constant(-1));
+
+        FunctionPollConfig<Integer, Integer> usingConstructor = new FunctionPollConfig<Integer, Integer>(SENSOR_INT)
+                .period(1)
+                .supplier(Suppliers.ofInstance(1))
+                .onSuccess(Functions.constant(-1));
+
+        FunctionPollConfig<Integer, Integer> usingConstructorWithFailureOrException = new FunctionPollConfig<Integer, Integer>(SENSOR_INT)
+                .period(1)
+                .supplier(Suppliers.ofInstance(1))
+                .onFailureOrException(Functions.<Integer>constant(null));
+    }
+    
+    
+    private void assertFeedIsPolling() {
+        final Integer val = entity.getAttribute(SENSOR_INT);
+        Asserts.succeedsEventually(new Runnable() {
+            @Override
+            public void run() {
+                assertNotEquals(val, entity.getAttribute(SENSOR_INT));
+            }
+        });
+    }
+    
+    private void assertFeedIsPollingContinuously() {
+        Asserts.succeedsContinually(new Runnable() {
+            @Override
+            public void run() {
+                assertFeedIsPolling();
+            }
+        });
+    }
+
+    private static class IncrementingCallable implements Callable<Integer> {
+        private final AtomicInteger next = new AtomicInteger(0);
+        
+        @Override public Integer call() {
+            return next.getAndIncrement();
+        }
+    }
+    
+    private static class AddOneFunction implements Function<Integer, Integer> {
+        @Override public Integer apply(@Nullable Integer input) {
+            return (input != null) ? (input + 1) : null;
+        }
+    }
+    
+    private static class ExceptionCallable implements Callable<Void> {
+        private final String msg;
+        ExceptionCallable(String msg) {
+            this.msg = msg;
+        }
+        @Override public Void call() {
+            throw new RuntimeException(msg);
+        }
+    }
+    
+    public static class ToStringFunction implements Function<Object, String> {
+        @Override public String apply(@Nullable Object input) {
+            return (input != null) ? (input.toString()) : null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/feed/http/HttpFeedIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/feed/http/HttpFeedIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/feed/http/HttpFeedIntegrationTest.java
new file mode 100644
index 0000000..ee7e226
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/feed/http/HttpFeedIntegrationTest.java
@@ -0,0 +1,160 @@
+/*
+ * 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.feed.http;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.net.URI;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.HttpService;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+
+import com.google.common.base.Functions;
+import com.google.common.collect.ImmutableList;
+
+public class HttpFeedIntegrationTest extends BrooklynAppUnitTestSupport {
+
+    final static AttributeSensor<String> SENSOR_STRING = Sensors.newStringSensor("aString", "");
+    final static AttributeSensor<Integer> SENSOR_INT = Sensors.newIntegerSensor("aLong", "");
+
+    private HttpService httpService;
+
+    private Location loc;
+    private EntityLocal entity;
+    private HttpFeed feed;
+    
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        loc = new LocalhostMachineProvisioningLocation();
+        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        app.start(ImmutableList.of(loc));
+    }
+
+    @AfterMethod(alwaysRun=true)
+    @Override
+    public void tearDown() throws Exception {
+        if (feed != null) feed.stop();
+        if (httpService != null) httpService.shutdown();
+        super.tearDown();
+    }
+
+    @Test(groups = {"Integration"})
+    public void testPollsAndParsesHttpGetResponseWithSsl() throws Exception {
+        httpService = new HttpService(PortRanges.fromString("9000+"), true).start();
+        URI baseUrl = new URI(httpService.getUrl());
+
+        assertEquals(baseUrl.getScheme(), "https", "baseUrl="+baseUrl);
+        
+        feed = HttpFeed.builder()
+                .entity(entity)
+                .baseUri(baseUrl)
+                .poll(new HttpPollConfig<Integer>(SENSOR_INT)
+                        .period(100)
+                        .onSuccess(HttpValueFunctions.responseCode()))
+                .poll(new HttpPollConfig<String>(SENSOR_STRING)
+                        .period(100)
+                        .onSuccess(HttpValueFunctions.stringContentsFunction()))
+                .build();
+        
+        EntityTestUtils.assertAttributeEqualsEventually(entity, SENSOR_INT, 200);
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                String val = entity.getAttribute(SENSOR_STRING);
+                assertTrue(val != null && val.contains("Hello, World"), "val="+val);
+            }});
+    }
+
+    @Test(groups = {"Integration"})
+    public void testPollsAndParsesHttpGetResponseWithBasicAuthentication() throws Exception {
+        final String username = "brooklyn";
+        final String password = "hunter2";
+        httpService = new HttpService(PortRanges.fromString("9000+"))
+                .basicAuthentication(username, password)
+                .start();
+        URI baseUrl = new URI(httpService.getUrl());
+        assertEquals(baseUrl.getScheme(), "http", "baseUrl="+baseUrl);
+
+        feed = HttpFeed.builder()
+                .entity(entity)
+                .baseUri(baseUrl)
+                .credentials(username, password)
+                .poll(new HttpPollConfig<Integer>(SENSOR_INT)
+                        .period(100)
+                        .onSuccess(HttpValueFunctions.responseCode()))
+                .poll(new HttpPollConfig<String>(SENSOR_STRING)
+                        .period(100)
+                        .onSuccess(HttpValueFunctions.stringContentsFunction()))
+                .build();
+
+        EntityTestUtils.assertAttributeEqualsEventually(entity, SENSOR_INT, 200);
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                String val = entity.getAttribute(SENSOR_STRING);
+                assertTrue(val != null && val.contains("Hello, World"), "val="+val);
+            }});
+    }
+
+    @Test(groups = {"Integration"})
+    public void testPollWithInvalidCredentialsFails() throws Exception {
+        httpService = new HttpService(PortRanges.fromString("9000+"))
+                .basicAuthentication("brooklyn", "hunter2")
+                .start();
+
+        feed = HttpFeed.builder()
+                .entity(entity)
+                .baseUri(httpService.getUrl())
+                .credentials("brooklyn", "9876543210")
+                .poll(new HttpPollConfig<Integer>(SENSOR_INT)
+                        .period(100)
+                        .onSuccess(HttpValueFunctions.responseCode())
+                        .onFailure(HttpValueFunctions.responseCode()))
+                .poll(new HttpPollConfig<String>(SENSOR_STRING)
+                        .period(100)
+                        .onSuccess(HttpValueFunctions.stringContentsFunction())
+                        .onException(Functions.constant("Failed!")))
+                .build();
+
+        EntityTestUtils.assertAttributeEqualsEventually(entity, SENSOR_INT, 401);
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                String val = entity.getAttribute(SENSOR_STRING);
+                assertTrue(val != null && val.equals("Failed!"), "val=" + val);
+            }
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/feed/http/HttpFeedTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/feed/http/HttpFeedTest.java b/core/src/test/java/org/apache/brooklyn/feed/http/HttpFeedTest.java
new file mode 100644
index 0000000..d8ac492
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/feed/http/HttpFeedTest.java
@@ -0,0 +1,392 @@
+/*
+ * 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.feed.http;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.net.URL;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.EntityFunctions;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.entity.EntityInternal.FeedSupport;
+import org.apache.brooklyn.core.feed.FeedConfig;
+import org.apache.brooklyn.core.feed.PollConfig;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.http.BetterMockWebServer;
+import org.apache.brooklyn.util.core.http.HttpToolResponse;
+import org.apache.brooklyn.util.guava.Functionals;
+import org.apache.brooklyn.util.net.Networking;
+import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.mockwebserver.MockResponse;
+import com.google.mockwebserver.SocketPolicy;
+
+public class HttpFeedTest extends BrooklynAppUnitTestSupport {
+
+    private static final Logger log = LoggerFactory.getLogger(HttpFeedTest.class);
+    
+    final static AttributeSensor<String> SENSOR_STRING = Sensors.newStringSensor("aString", "");
+    final static AttributeSensor<Integer> SENSOR_INT = Sensors.newIntegerSensor( "aLong", "");
+
+    private static final long TIMEOUT_MS = 10*1000;
+    
+    private BetterMockWebServer server;
+    private URL baseUrl;
+    
+    private Location loc;
+    private EntityLocal entity;
+    private HttpFeed feed;
+    
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        server = BetterMockWebServer.newInstanceLocalhost();
+        for (int i = 0; i < 100; i++) {
+            server.enqueue(new MockResponse().setResponseCode(200).addHeader("content-type: application/json").setBody("{\"foo\":\"myfoo\"}"));
+        }
+        server.play();
+        baseUrl = server.getUrl("/");
+
+        loc = app.newLocalhostProvisioningLocation();
+        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        app.start(ImmutableList.of(loc));
+    }
+
+    @AfterMethod(alwaysRun=true)
+    @Override
+    public void tearDown() throws Exception {
+        if (feed != null) feed.stop();
+        if (server != null) server.shutdown();
+        feed = null;
+        super.tearDown();
+    }
+    
+    @Test
+    public void testPollsAndParsesHttpGetResponse() throws Exception {
+        feed = HttpFeed.builder()
+                .entity(entity)
+                .baseUrl(baseUrl)
+                .poll(HttpPollConfig.forSensor(SENSOR_INT)
+                        .period(100)
+                        .onSuccess(HttpValueFunctions.responseCode()))
+                .poll(HttpPollConfig.forSensor(SENSOR_STRING)
+                        .period(100)
+                        .onSuccess(HttpValueFunctions.stringContentsFunction()))
+                .build();
+        
+        assertSensorEventually(SENSOR_INT, (Integer)200, TIMEOUT_MS);
+        assertSensorEventually(SENSOR_STRING, "{\"foo\":\"myfoo\"}", TIMEOUT_MS);
+    }
+    
+    @Test
+    public void testFeedDeDupe() throws Exception {
+        testPollsAndParsesHttpGetResponse();
+        entity.addFeed(feed);
+        log.info("Feed 0 is: "+feed);
+        
+        testPollsAndParsesHttpGetResponse();
+        log.info("Feed 1 is: "+feed);
+        entity.addFeed(feed);
+                
+        FeedSupport feeds = ((EntityInternal)entity).feeds();
+        Assert.assertEquals(feeds.getFeeds().size(), 1, "Wrong feed count: "+feeds.getFeeds());
+    }
+    
+    @Test
+    public void testSetsConnectionTimeout() throws Exception {
+        feed = HttpFeed.builder()
+                .entity(entity)
+                .baseUrl(baseUrl)
+                .poll(new HttpPollConfig<Integer>(SENSOR_INT)
+                        .period(100)
+                        .connectionTimeout(Duration.TEN_SECONDS)
+                        .socketTimeout(Duration.TEN_SECONDS)
+                        .onSuccess(HttpValueFunctions.responseCode()))
+                .build();
+        
+        assertSensorEventually(SENSOR_INT, (Integer)200, TIMEOUT_MS);
+    }
+    
+    // TODO How to cause the other end to just freeze (similar to aws-ec2 when securityGroup port is not open)?
+    @Test
+    public void testSetsConnectionTimeoutWhenServerDisconnects() throws Exception {
+        if (server != null) server.shutdown();
+        server = BetterMockWebServer.newInstanceLocalhost();
+        for (int i = 0; i < 100; i++) {
+            server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.DISCONNECT_AT_START));
+        }
+        server.play();
+        baseUrl = server.getUrl("/");
+
+        feed = HttpFeed.builder()
+                .entity(entity)
+                .baseUrl(baseUrl)
+                .poll(new HttpPollConfig<Integer>(SENSOR_INT)
+                        .period(100)
+                        .connectionTimeout(Duration.TEN_SECONDS)
+                        .socketTimeout(Duration.TEN_SECONDS)
+                        .onSuccess(HttpValueFunctions.responseCode())
+                        .onException(Functions.constant(-1)))
+                .build();
+        
+        assertSensorEventually(SENSOR_INT, -1, TIMEOUT_MS);
+    }
+    
+    
+    @Test
+    public void testPollsAndParsesHttpPostResponse() throws Exception {
+        feed = HttpFeed.builder()
+                .entity(entity)
+                .baseUrl(baseUrl)
+                .poll(new HttpPollConfig<Integer>(SENSOR_INT)
+                        .method("post")
+                        .period(100)
+                        .onSuccess(HttpValueFunctions.responseCode()))
+                .poll(new HttpPollConfig<String>(SENSOR_STRING)
+                        .method("post")
+                        .period(100)
+                        .onSuccess(HttpValueFunctions.stringContentsFunction()))
+                .build();
+        
+        assertSensorEventually(SENSOR_INT, (Integer)200, TIMEOUT_MS);
+        assertSensorEventually(SENSOR_STRING, "{\"foo\":\"myfoo\"}", TIMEOUT_MS);
+    }
+
+    @Test
+    public void testUsesFailureHandlerOn4xx() throws Exception {
+        server = BetterMockWebServer.newInstanceLocalhost();
+        for (int i = 0; i < 100; i++) {
+            server.enqueue(new MockResponse()
+                    .setResponseCode(401)
+                    .setBody("Unauthorised"));
+        }
+        server.play();
+        feed = HttpFeed.builder()
+                .entity(entity)
+                .baseUrl(server.getUrl("/"))
+                .poll(new HttpPollConfig<Integer>(SENSOR_INT)
+                        .period(100)
+                        .onSuccess(HttpValueFunctions.responseCode())
+                        .onFailure(HttpValueFunctions.responseCode()))
+                .poll(new HttpPollConfig<String>(SENSOR_STRING)
+                        .period(100)
+                        .onSuccess(HttpValueFunctions.stringContentsFunction())
+                        .onFailure(Functions.constant("Failed")))
+                .build();
+
+        assertSensorEventually(SENSOR_INT, 401, TIMEOUT_MS);
+        assertSensorEventually(SENSOR_STRING, "Failed", TIMEOUT_MS);
+
+        server.shutdown();
+    }
+
+    @Test
+    public void testUsesExceptionHandlerOn4xxAndNoFailureHandler() throws Exception {
+        server = BetterMockWebServer.newInstanceLocalhost();
+        for (int i = 0; i < 100; i++) {
+            server.enqueue(new MockResponse()
+                    .setResponseCode(401)
+                    .setBody("Unauthorised"));
+        }
+        server.play();
+        feed = HttpFeed.builder()
+                .entity(entity)
+                .baseUrl(server.getUrl("/"))
+                .poll(new HttpPollConfig<Integer>(SENSOR_INT)
+                        .period(100)
+                        .onSuccess(HttpValueFunctions.responseCode())
+                        .onException(Functions.constant(-1)))
+                .build();
+
+        assertSensorEventually(SENSOR_INT, -1, TIMEOUT_MS);
+
+        server.shutdown();
+    }
+
+    @Test(groups="Integration")
+    // marked integration as it takes a wee while
+    public void testSuspendResume() throws Exception {
+        feed = HttpFeed.builder()
+                .entity(entity)
+                .baseUrl(baseUrl)
+                .poll(new HttpPollConfig<Integer>(SENSOR_INT)
+                        .period(100)
+                        .onSuccess(HttpValueFunctions.responseCode()))
+                .poll(new HttpPollConfig<String>(SENSOR_STRING)
+                        .period(100)
+                        .onSuccess(HttpValueFunctions.stringContentsFunction()))
+                .build();
+        assertSensorEventually(SENSOR_INT, (Integer)200, TIMEOUT_MS);
+        feed.suspend();
+        final int countWhenSuspended = server.getRequestCount();
+        
+        Thread.sleep(500);
+        if (server.getRequestCount() > countWhenSuspended+1)
+            Assert.fail("Request count continued to increment while feed was suspended, from "+countWhenSuspended+" to "+server.getRequestCount());
+        
+        feed.resume();
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                assertTrue(server.getRequestCount() > countWhenSuspended + 1,
+                        "Request count failed to increment when feed was resumed, from " + countWhenSuspended + ", still at " + server.getRequestCount());
+            }
+        });
+    }
+
+    @Test(groups="Integration")
+    // marked integration as it takes a wee while
+    public void testStartSuspended() throws Exception {
+        feed = HttpFeed.builder()
+                .entity(entity)
+                .baseUrl(baseUrl)
+                .poll(HttpPollConfig.forSensor(SENSOR_INT)
+                        .period(100)
+                        .onSuccess(HttpValueFunctions.responseCode()))
+                .poll(HttpPollConfig.forSensor(SENSOR_STRING)
+                        .period(100)
+                        .onSuccess(HttpValueFunctions.stringContentsFunction()))
+                .suspended()
+                .build();
+        Asserts.continually(MutableMap.of("timeout", 500),
+                Entities.attributeSupplier(entity, SENSOR_INT), Predicates.<Integer>equalTo(null));
+        int countWhenSuspended = server.getRequestCount();
+        feed.resume();
+        Asserts.eventually(Entities.attributeSupplier(entity, SENSOR_INT), Predicates.<Integer>equalTo(200));
+        if (server.getRequestCount() <= countWhenSuspended)
+            Assert.fail("Request count failed to increment when feed was resumed, from "+countWhenSuspended+", still at "+server.getRequestCount());
+        log.info("RUN: "+countWhenSuspended+" - "+server.getRequestCount());
+    }
+
+
+    @Test
+    public void testPollsAndParsesHttpErrorResponseLocal() throws Exception {
+        int unboundPort = Networking.nextAvailablePort(10000);
+        feed = HttpFeed.builder()
+                .entity(entity)
+                .baseUri("http://localhost:" + unboundPort + "/path/should/not/exist")
+                .poll(new HttpPollConfig<String>(SENSOR_STRING)
+                        .onSuccess(Functions.constant("success"))
+                        .onFailure(Functions.constant("failure"))
+                        .onException(Functions.constant("error")))
+                .build();
+        
+        assertSensorEventually(SENSOR_STRING, "error", TIMEOUT_MS);
+    }
+
+    @Test
+    public void testPollsMulti() throws Exception {
+        newMultiFeed(baseUrl);
+        assertSensorEventually(SENSOR_INT, (Integer)200, TIMEOUT_MS);
+        assertSensorEventually(SENSOR_STRING, "{\"foo\":\"myfoo\"}", TIMEOUT_MS);
+    }
+
+    // because takes a wee while
+    @SuppressWarnings("rawtypes")
+    @Test(groups="Integration")
+    public void testPollsMultiClearsOnSubsequentFailure() throws Exception {
+        server = BetterMockWebServer.newInstanceLocalhost();
+        for (int i = 0; i < 10; i++) {
+            server.enqueue(new MockResponse()
+                    .setResponseCode(200)
+                    .setBody("Hello World"));
+        }
+        for (int i = 0; i < 10; i++) {
+            server.enqueue(new MockResponse()
+                    .setResponseCode(401)
+                    .setBody("Unauthorised"));
+        }
+        server.play();
+
+        newMultiFeed(server.getUrl("/"));
+        
+        assertSensorEventually(SENSOR_INT, 200, TIMEOUT_MS);
+        assertSensorEventually(SENSOR_STRING, "Hello World", TIMEOUT_MS);
+        
+        assertSensorEventually(SENSOR_INT, -1, TIMEOUT_MS);
+        assertSensorEventually(SENSOR_STRING, null, TIMEOUT_MS);
+        
+        List<String> attrs = Lists.transform(MutableList.copyOf( ((EntityInternal)entity).getAllAttributes().keySet() ),
+            new Function<AttributeSensor,String>() {
+                @Override public String apply(AttributeSensor input) { return input.getName(); } });
+        Assert.assertTrue(!attrs.contains(SENSOR_STRING.getName()), "attrs contained "+SENSOR_STRING);
+        Assert.assertTrue(!attrs.contains(FeedConfig.NO_SENSOR.getName()), "attrs contained "+FeedConfig.NO_SENSOR);
+        
+        server.shutdown();
+    }
+
+    private void newMultiFeed(URL baseUrl) {
+        feed = HttpFeed.builder()
+                .entity(entity)
+                .baseUrl(baseUrl)
+                
+                .poll(HttpPollConfig.forMultiple()
+                    .onSuccess(new Function<HttpToolResponse,Void>() {
+                        public Void apply(HttpToolResponse response) {
+                            entity.setAttribute(SENSOR_INT, response.getResponseCode());
+                            if (response.getResponseCode()==200)
+                                entity.setAttribute(SENSOR_STRING, response.getContentAsString());
+                            return null;
+                        }
+                    })
+                    .onFailureOrException(Functionals.function(EntityFunctions.settingSensorsConstant(entity, MutableMap.<AttributeSensor<?>,Object>of(
+                        SENSOR_INT, -1, 
+                        SENSOR_STRING, PollConfig.REMOVE))))
+                .period(100))
+                .build();
+    }
+    
+
+    private <T> void assertSensorEventually(final AttributeSensor<T> sensor, final T expectedVal, long timeout) {
+        Asserts.succeedsEventually(ImmutableMap.of("timeout", timeout), new Callable<Void>() {
+            public Void call() {
+                assertEquals(entity.getAttribute(sensor), expectedVal);
+                return null;
+            }
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/feed/http/HttpValueFunctionsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/feed/http/HttpValueFunctionsTest.java b/core/src/test/java/org/apache/brooklyn/feed/http/HttpValueFunctionsTest.java
new file mode 100644
index 0000000..23ffae3
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/feed/http/HttpValueFunctionsTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.feed.http;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.NoSuchElementException;
+
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
+import org.apache.brooklyn.util.core.http.HttpToolResponse;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonPrimitive;
+
+public class HttpValueFunctionsTest {
+
+    private int responseCode = 200;
+    private long fullLatency = 1000;
+    private String headerName = "my_header";
+    private String headerVal = "my_header_val";
+    private String bodyKey = "mykey";
+    private String bodyVal = "myvalue";
+    private String body = "{"+bodyKey+":"+bodyVal+"}";
+    private long now;
+    private HttpToolResponse response;
+    
+    @BeforeMethod
+    public void setUp() throws Exception {
+        now = System.currentTimeMillis();
+        response = new HttpToolResponse(responseCode, ImmutableMap.of(headerName, ImmutableList.of(headerVal)), 
+                body.getBytes(), now-fullLatency, fullLatency / 2, fullLatency);
+    }
+    
+    @Test
+    public void testResponseCode() throws Exception {
+        assertEquals(HttpValueFunctions.responseCode().apply(response), Integer.valueOf(responseCode));
+    }
+
+    @Test
+    public void testContainsHeader() throws Exception {
+        assertTrue(HttpValueFunctions.containsHeader(headerName).apply(response));
+        assertFalse(HttpValueFunctions.containsHeader("wrong_header").apply(response));
+    }
+    
+    @Test
+    public void testStringContents() throws Exception {
+        assertEquals(HttpValueFunctions.stringContentsFunction().apply(response), body);
+    }
+
+    @Test
+    public void testJsonContents() throws Exception {
+        JsonElement json = HttpValueFunctions.jsonContents().apply(response);
+        assertTrue(json.isJsonObject());
+        assertEquals(json.getAsJsonObject().entrySet(), ImmutableMap.of(bodyKey, new JsonPrimitive(bodyVal)).entrySet());
+    }
+
+    @Test
+    public void testJsonContentsGettingElement() throws Exception {
+        assertEquals(HttpValueFunctions.jsonContents(bodyKey, String.class).apply(response), bodyVal);
+    }
+
+    @Test(expectedExceptions=NoSuchElementException.class)
+    public void testJsonContentsGettingMissingElement() throws Exception {
+        assertNull(HttpValueFunctions.jsonContents("wrongkey", String.class).apply(response));
+    }
+
+    @Test
+    public void testLatency() throws Exception {
+        assertEquals(HttpValueFunctions.latency().apply(response), Long.valueOf(fullLatency));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/core/src/test/java/org/apache/brooklyn/feed/http/JsonFunctionsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/feed/http/JsonFunctionsTest.java b/core/src/test/java/org/apache/brooklyn/feed/http/JsonFunctionsTest.java
new file mode 100644
index 0000000..928035e
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/feed/http/JsonFunctionsTest.java
@@ -0,0 +1,130 @@
+/*
+ * 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.feed.http;
+
+import java.util.NoSuchElementException;
+
+import org.apache.brooklyn.feed.http.JsonFunctions;
+import org.apache.brooklyn.util.collections.Jsonya;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.collections.Jsonya.Navigator;
+import org.apache.brooklyn.util.guava.Functionals;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import com.jayway.jsonpath.PathNotFoundException;
+
+public class JsonFunctionsTest {
+
+    public static JsonElement europeMap() {
+        Navigator<MutableMap<Object, Object>> europe = Jsonya.newInstance().at("europe", "uk", "edinburgh")
+                .put("population", 500*1000)
+                .put("weather", "wet", "lighting", "dark")
+                .root().at("europe").at("france").put("population", 80*1000*1000)
+                .root();
+        return new JsonParser().parse( europe.toString() );
+    }
+
+    @Test
+    public void testWalk1() {
+        JsonElement pop = JsonFunctions.walk("europe", "france", "population").apply(europeMap());
+        Assert.assertEquals( (int)JsonFunctions.cast(Integer.class).apply(pop), 80*1000*1000 );
+    }
+
+    @Test
+    public void testWalk2() {
+        String weather = Functionals.chain(
+            JsonFunctions.walk("europe.uk.edinburgh.weather"),
+            JsonFunctions.cast(String.class) ).apply(europeMap());
+        Assert.assertEquals(weather, "wet");
+    }
+
+    @Test(expectedExceptions=NoSuchElementException.class)
+    public void testWalkWrong() {
+        Functionals.chain(
+            JsonFunctions.walk("europe", "spain", "barcelona"),
+            JsonFunctions.cast(String.class) ).apply(europeMap());
+    }
+
+
+    @Test
+    public void testWalkM() {
+        Maybe<JsonElement> pop = JsonFunctions.walkM("europe", "france", "population").apply( Maybe.of(europeMap()) );
+        Assert.assertEquals( (int)JsonFunctions.castM(Integer.class).apply(pop), 80*1000*1000 );
+    }
+
+    @Test
+    public void testWalkMWrong1() {
+        Maybe<JsonElement> m = JsonFunctions.walkM("europe", "spain", "barcelona").apply( Maybe.of( europeMap()) );
+        Assert.assertTrue(m.isAbsent());
+    }
+
+    @Test(expectedExceptions=Exception.class)
+    public void testWalkMWrong2() {
+        Maybe<JsonElement> m = JsonFunctions.walkM("europe", "spain", "barcelona").apply( Maybe.of( europeMap()) );
+        JsonFunctions.castM(String.class).apply(m);
+    }
+
+    
+    @Test
+    public void testWalkN() {
+        JsonElement pop = JsonFunctions.walkN("europe", "france", "population").apply( europeMap() );
+        Assert.assertEquals( (int)JsonFunctions.cast(Integer.class).apply(pop), 80*1000*1000 );
+    }
+
+    @Test
+    public void testWalkNWrong1() {
+        JsonElement m = JsonFunctions.walkN("europe", "spain", "barcelona").apply( europeMap() );
+        Assert.assertNull(m);
+    }
+
+    public void testWalkNWrong2() {
+        JsonElement m = JsonFunctions.walkN("europe", "spain", "barcelona").apply( europeMap() );
+        String n = JsonFunctions.cast(String.class).apply(m);
+        Assert.assertNull(n);
+    }
+
+    @Test
+    public void testGetPath1(){
+        Integer obj = (Integer) JsonFunctions.getPath("$.europe.uk.edinburgh.population").apply(europeMap());
+        Assert.assertEquals((int) obj, 500*1000);
+    }
+
+    @Test
+    public void testGetPath2(){
+        String obj = (String) JsonFunctions.getPath("$.europe.uk.edinburgh.lighting").apply(europeMap());
+        Assert.assertEquals(obj, "dark");
+    }
+
+    @Test
+    public void testGetMissingPathIsNullOrThrows(){
+        try {
+            // TODO is there a way to force this to return null if not found?
+            // for me (Alex) it throws but for others it seems to return null
+            Object obj = JsonFunctions.getPath("$.europe.spain.malaga").apply(europeMap());
+            Assert.assertNull(obj);
+        } catch (PathNotFoundException e) {
+            // not unexpected
+        }
+    }
+    
+}


[06/36] incubator-brooklyn git commit: Rename o.a.b.effector.core to o.a.b.core.effector

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java
new file mode 100644
index 0000000..76dcdba
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java
@@ -0,0 +1,173 @@
+/*
+ * 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.core.effector;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.effector.ParameterType;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.api.mgmt.ExecutionContext;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.annotation.EffectorParam;
+import org.apache.brooklyn.core.effector.MethodEffector;
+import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.task.BasicTask;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+
+/**
+ * Test the operation of the {@link Effector} implementations.
+ *
+ * TODO clarify test purpose
+ */
+public class EffectorSayHiTest extends BrooklynAppUnitTestSupport {
+    
+    //TODO test edge/error conditions
+    //(missing parameters, wrong number of params, etc)
+
+    private static final Logger log = LoggerFactory.getLogger(EffectorSayHiTest.class);
+
+    private MyEntity e;
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        e = app.createAndManageChild(EntitySpec.create(MyEntity.class));
+    }
+
+    @Test
+    public void testFindEffectorMetaData() {
+        assertEquals("sayHi1", e.SAY_HI_1.getName());
+        assertEquals("says hello", e.SAY_HI_1.getDescription());
+        
+        assertEquals(ImmutableList.of("name", "greeting"), getParameterNames(e.SAY_HI_1));
+        assertEquals(MutableMap.of("name", null, "greeting", "what to say"), getParameterDescriptions(e.SAY_HI_1));
+    }
+
+    @Test
+    public void testFindTraitEffectors() {
+        assertEquals(ImmutableList.of("locations"), getParameterNames(Startable.START));
+    }
+
+    @Test
+    public void testInvokeEffectors1() throws Exception {
+        assertEquals("hi Bob", e.sayHi1("Bob", "hi"));
+
+        assertEquals("hi Bob", e.SAY_HI_1.call(e, ImmutableMap.of("name", "Bob", "greeting", "hi")) );
+        assertEquals("hi Bob", e.invoke(e.SAY_HI_1, ImmutableMap.of("name", "Bob", "greeting", "hi")).get() );
+        
+        // and with default greeting param value
+        assertEquals("hi Bob", e.SAY_HI_1.call(e, ImmutableMap.of("name", "Bob", "greeting", "hi")) );
+        assertEquals("hello Bob", e.invoke(e.SAY_HI_1, ImmutableMap.of("name", "Bob")).get() );
+    }
+
+    @Test
+    public void testCanRetrieveTaskForEffector() {
+        e.sayHi1("Bob", "hi");
+
+        Set<Task<?>> tasks = mgmt.getExecutionManager().getTasksWithAllTags(ImmutableList.of(
+                BrooklynTaskTags.tagForContextEntity(e),ManagementContextInternal.EFFECTOR_TAG));
+        assertEquals(tasks.size(), 1);
+        assertTrue(tasks.iterator().next().getDescription().contains("sayHi1"));
+    }
+
+    @Test
+    public void testDelegatedNestedEffectorNotRepresentedAsTask() {
+        e.delegateSayHi1("Bob", "hi");
+
+        Set<Task<?>> tasks = mgmt.getExecutionManager().getTasksWithAllTags(ImmutableList.of(
+                BrooklynTaskTags.tagForContextEntity(e),ManagementContextInternal.EFFECTOR_TAG));
+        assertEquals(tasks.size(), 1);
+        assertTrue(tasks.iterator().next().getDescription().contains("delegateSayHi1"));
+        assertFalse(tasks.iterator().next().getDescription().contains("sayHi1"));
+    }
+
+    @Test
+    public void testCanExcludeNonEffectorTasks() throws Exception {
+        ExecutionContext executionContext = mgmt.getExecutionContext(e);
+        executionContext.submit(new BasicTask<Void>(new Runnable() { public void run() {} }));
+
+        Set<Task<?>> effectTasks = mgmt.getExecutionManager().getTasksWithAllTags(ImmutableList.of(
+                BrooklynTaskTags.tagForContextEntity(e),ManagementContextInternal.EFFECTOR_TAG));
+        assertEquals(effectTasks.size(), 0);
+    }
+
+    public interface CanSayHi {
+        static MethodEffector<String> SAY_HI_1 = new MethodEffector<String>(CanSayHi.class, "sayHi1");
+        static MethodEffector<String> DELEGATE_SAY_HI_1 = new MethodEffector<String>(CanSayHi.class, "delegateSayHi1");
+    
+        @org.apache.brooklyn.core.annotation.Effector(description="says hello")
+        public String sayHi1(
+            @EffectorParam(name="name") String name,
+            @EffectorParam(name="greeting", defaultValue="hello", description="what to say") String greeting);
+        
+        @org.apache.brooklyn.core.annotation.Effector(description="delegate says hello")
+        public String delegateSayHi1(
+            @EffectorParam(name="name") String name,
+            @EffectorParam(name="greeting") String greeting);
+    }
+
+    @ImplementedBy(MyEntityImpl.class)
+    public interface MyEntity extends Entity, CanSayHi {
+    }
+    
+    public static class MyEntityImpl extends AbstractEntity implements MyEntity {
+        @Override
+        public String sayHi1(String name, String greeting) {
+            return greeting+" "+name;
+        }
+        @Override
+        public String delegateSayHi1(String name, String greeting) {
+            return sayHi1(name, greeting);
+        }
+    }
+    
+    private List<String> getParameterNames(Effector<?> effector) {
+        return ImmutableList.copyOf(getParameterDescriptions(effector).keySet());
+    }
+    
+    private Map<String, String> getParameterDescriptions(Effector<?> effector) {
+        Map<String,String> result = Maps.newLinkedHashMap();
+        for (ParameterType<?> parameter : effector.getParameters()) {
+            result.put(parameter.getName(), parameter.getDescription());
+        }
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorTaskTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorTaskTest.java b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorTaskTest.java
new file mode 100644
index 0000000..3e79aa9
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorTaskTest.java
@@ -0,0 +1,437 @@
+/*
+ * 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.core.effector;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.mgmt.HasTaskChildren;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.effector.EffectorBody;
+import org.apache.brooklyn.core.effector.EffectorTasks;
+import org.apache.brooklyn.core.effector.EffectorWithBody;
+import org.apache.brooklyn.core.effector.Effectors;
+import org.apache.brooklyn.core.effector.EffectorTasks.EffectorTaskFactory;
+import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.core.task.DynamicSequentialTask;
+import org.apache.brooklyn.util.core.task.DynamicTasks;
+import org.apache.brooklyn.util.core.task.TaskBuilder;
+import org.apache.brooklyn.util.core.task.Tasks;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+
+public class EffectorTaskTest extends BrooklynAppUnitTestSupport {
+
+    // ----------- syntax 1 -- effector with body in a class
+    
+    public static final Effector<Integer> DOUBLE_1 = Effectors.effector(Integer.class, "double")
+            .description("doubles the given number")
+            .parameter(Integer.class, "numberToDouble")
+            .impl(new EffectorBody<Integer>() {
+                @Override
+                public Integer call(ConfigBag parameters) {
+                    // do a sanity check
+                    Assert.assertNotNull(entity());
+                    
+                    // finally double the input
+                    return 2*(Integer)parameters.getStringKey("numberToDouble");
+                }
+            })
+            .build();
+
+    public static class DoublingEntity extends AbstractEntity {
+        public static final Effector<Integer> DOUBLE = EffectorTaskTest.DOUBLE_1;
+    }
+
+    @Test
+    public void testSyntaxOneDouble1() throws Exception {
+        // just use "dynamic" support of effector
+        Assert.assertEquals(app.invoke(DOUBLE_1, MutableMap.of("numberToDouble", 3)).get(), (Integer)6);
+    }
+    
+    @Test
+    public void testSyntaxOneTaggedCorrectly() throws Exception {
+        Task<Integer> t = app.invoke(DOUBLE_1, MutableMap.of("numberToDouble", 3));
+        t.get();
+        checkTags(t, app, DOUBLE_1, false);
+    }
+    
+    @Test
+    // also assert it works when the effector is defined on an entity
+    public void testSimpleEffectorOnEntity() throws Exception {
+        Entity doubler = app.createAndManageChild(EntitySpec.create(Entity.class, DoublingEntity.class));
+        
+        Assert.assertEquals(doubler.invoke(DOUBLE_1, MutableMap.of("numberToDouble", 3)).get(), (Integer)6);
+    }
+
+    @Test
+    // also assert it works when an abstract effector name is passed in to the entity
+    public void testSimpleEffectorNameMatching() throws Exception {
+        Entity doubler = app.createAndManageChild(EntitySpec.create(Entity.class, DoublingEntity.class));
+        
+        Assert.assertEquals(doubler.invoke(Effectors.effector(Integer.class, "double").buildAbstract(), MutableMap.of("numberToDouble", 3)).get(), (Integer)6);
+    }
+
+
+    // ----------- syntax 2 -- effector with body built with fluent API
+    
+    public static EffectorTaskFactory<Integer> times(final EffectorTaskFactory<Integer> x, final int y) {
+        return new EffectorTaskFactory<Integer>() {
+            @Override
+            public Task<Integer> newTask(final Entity entity, final Effector<Integer> effector, final ConfigBag parameters) {
+                return TaskBuilder.<Integer>builder().name("times").body(new Callable<Integer>() { public Integer call() { 
+                    return DynamicTasks.get( x.newTask(entity, effector, parameters) )*y; 
+                } }).build();
+            }
+        };
+    }
+
+    public static final Effector<Integer> DOUBLE_2 = Effectors.effector(Integer.class, "double")
+            .description("doubles the given number")
+            .parameter(Integer.class, "numberToDouble")
+            .impl(times(EffectorTasks.parameter(Integer.class, "numberToDouble"), 2))
+            .build();
+
+    @Test
+    public void testSyntaxTwoDouble2() throws Exception {
+        Assert.assertEquals(app.invoke(DOUBLE_2, MutableMap.of("numberToDouble", 3)).get(), (Integer)6);
+    }
+
+    @Test
+    public void testEffectorImplTaggedCorrectly() throws Exception {
+        Task<Integer> t = app.invoke(DOUBLE_2, MutableMap.of("numberToDouble", 3));
+        t.get();
+        checkTags(t, app, DOUBLE_2, true);
+    }
+
+    public static final Effector<Integer> DOUBLE_CALL_ABSTRACT = Effectors.effector(Integer.class, "double_call")
+        .description("doubles the given number")
+        .parameter(Integer.class, "numberToDouble")
+        .buildAbstract();
+    public static final Effector<Integer> DOUBLE_CALL = Effectors.effector(DOUBLE_CALL_ABSTRACT)
+        .impl(new EffectorBody<Integer>() {
+            @Override
+            public Integer call(ConfigBag parameters) {
+                final Entity parent = entity();
+                final Entity child = Iterables.getOnlyElement(entity().getChildren());
+                
+                final Effector<Integer> DOUBLE_CHECK_ABSTRACT = Effectors.effector(Integer.class, "double_check")
+                    .description("doubles the given number and checks tags, assuming double exists as an effector here")
+                    .parameter(Integer.class, "numberToDouble")
+                    .buildAbstract();
+                Effector<Integer> DOUBLE_CHECK = Effectors.effector(DOUBLE_CHECK_ABSTRACT)
+                    .impl(new EffectorBody<Integer>() {
+                        @Override
+                        public Integer call(ConfigBag parameters) {
+                            Assert.assertTrue(BrooklynTaskTags.isInEffectorTask(Tasks.current(), child, null, false));
+                            Assert.assertTrue(BrooklynTaskTags.isInEffectorTask(Tasks.current(), child, DOUBLE_CHECK_ABSTRACT, false));
+                            Assert.assertFalse(BrooklynTaskTags.isInEffectorTask(Tasks.current(), child, DOUBLE_1, false));
+                            Assert.assertTrue(BrooklynTaskTags.isInEffectorTask(Tasks.current(), parent, null, true));
+                            Assert.assertFalse(BrooklynTaskTags.isInEffectorTask(Tasks.current(), parent, null, false));
+                            Assert.assertTrue(BrooklynTaskTags.isInEffectorTask(Tasks.current(), parent, DOUBLE_CALL_ABSTRACT, true));
+                            Assert.assertFalse(BrooklynTaskTags.isInEffectorTask(Tasks.current(), parent, DOUBLE_1, true));
+                            
+                            return entity().invoke(DOUBLE_1, parameters.getAllConfig()).getUnchecked();
+                        }
+                    }).build();
+
+                return child.invoke(DOUBLE_CHECK, parameters.getAllConfig()).getUnchecked();
+            }
+        }).build();
+
+
+    @Test
+    // also assert it works when the effector is defined on an entity
+    public void testNestedEffectorTag() throws Exception {
+        app.createAndManageChild(EntitySpec.create(Entity.class, DoublingEntity.class));
+        Assert.assertEquals(app.invoke(DOUBLE_CALL, MutableMap.of("numberToDouble", 3)).get(), (Integer)6);
+    }
+
+
+    private void checkTags(Task<Integer> t, Entity entity, Effector<?> eff, boolean shouldHaveChild) {
+        Assert.assertEquals(BrooklynTaskTags.getContextEntity(t), app);
+        Assert.assertTrue(t.getTags().contains(BrooklynTaskTags.EFFECTOR_TAG), "missing effector tag; had: "+t.getTags());
+        Assert.assertTrue(t.getDescription().contains(eff.getName()), "description missing effector name: "+t.getDescription());
+        Assert.assertTrue(BrooklynTaskTags.isInEffectorTask(t, entity, eff, false));
+        Assert.assertTrue(BrooklynTaskTags.isInEffectorTask(t, null, null, false));
+        Assert.assertFalse(BrooklynTaskTags.isInEffectorTask(t, entity, Startable.START, false));
+        
+        if (shouldHaveChild) {
+            Task<?> subtask = ((HasTaskChildren)t).getChildren().iterator().next();
+            Assert.assertTrue(BrooklynTaskTags.isInEffectorTask(subtask, entity, eff, false));
+            Assert.assertTrue(BrooklynTaskTags.isInEffectorTask(subtask, null, null, false));
+        }
+    }
+
+    // TEST parameter task missing
+    
+    // ----------------- syntax for more complex -- an effector using subtasks
+    
+    public static Task<Integer> add(final int x, final int y) {
+        return TaskBuilder.<Integer>builder().name("add").body(new Callable<Integer>() { public Integer call() { return x+y; } }).build();
+    }
+
+    public static Task<Integer> add(final Task<Integer> x, final int y) {
+        return TaskBuilder.<Integer>builder().name("add").body(new Callable<Integer>() { public Integer call() { return DynamicTasks.get(x)+y; } }).build();
+    }
+
+    public static Task<Integer> addBasic(final Task<Integer> x, final int y) {
+        return TaskBuilder.<Integer>builder().name("add (not dynamic)").dynamic(false).body(new Callable<Integer>() { public Integer call() {
+            Preconditions.checkState(x.isSubmitted()); 
+            return x.getUnchecked()+y; 
+        } }).build();
+    }
+
+    public static Task<Integer> times(final int x, final int y) {
+        return TaskBuilder.<Integer>builder().name("times").body(new Callable<Integer>() { public Integer call() { return x*y; } }).build();
+    }
+
+    public static Task<Integer> times(final Task<Integer> x, final int y) {
+        return TaskBuilder.<Integer>builder().name("times").body(new Callable<Integer>() { public Integer call() { return DynamicTasks.get(x)*y; } }).build();
+    }
+    
+    public static final Effector<Integer> TWO_X_PLUS_ONE = Effectors.effector(Integer.class, "twoXPlusOne")
+            .description("doubles the given number and adds one")
+            .parameter(Integer.class, "numberToStartWith")
+            .impl(new EffectorBody<Integer>() {
+                public Integer call(ConfigBag parameters) {
+                    int input = (Integer)parameters.getStringKey("numberToStartWith");
+                    queue( add(times(input, 2), 1) );
+                    return last(Integer.class);
+                }
+            })
+            .build();
+
+    public static final Effector<Integer> TWO_X_PLUS_ONE_BASIC = Effectors.effector(Integer.class, "twoXPlusOne_Basic")
+            .description("doubles the given number and adds one, as a basic task")
+            .parameter(Integer.class, "numberToStartWith")
+            .impl(new EffectorBody<Integer>() {
+                public Integer call(ConfigBag parameters) {
+                    int input = (Integer)parameters.getStringKey("numberToStartWith");
+                    // note the subtasks must be queued explicitly with a basic task
+                    // (but with the DynamicSequentialTask they can be resolved by the task itself; see above)
+                    Task<Integer> product = queue(times(input, 2));
+                    queue( addBasic(product, 1) );
+                    return last(Integer.class);
+                }
+            })
+            .build();
+
+    // TODO a chaining style approach
+    
+    public static class Txp1Entity extends AbstractEntity {
+        public static final Effector<Integer> TWO_X_P_1 = EffectorTaskTest.TWO_X_PLUS_ONE;
+    }
+
+    /** the composed effector should allow us to inspect its children */
+    @Test
+    public void testComposedEffector() throws Exception {
+        Entity txp1 = app.createAndManageChild(EntitySpec.create(Entity.class, Txp1Entity.class));
+        
+        Task<Integer> e = txp1.invoke(TWO_X_PLUS_ONE, MutableMap.of("numberToStartWith", 3));
+        Assert.assertTrue(e instanceof DynamicSequentialTask);
+        Assert.assertEquals(e.get(), (Integer)7);
+        Assert.assertEquals( Iterables.size( ((HasTaskChildren)e).getChildren() ), 1);
+        Task<?> child = ((HasTaskChildren)e).getChildren().iterator().next();
+        Assert.assertEquals( Iterables.size( ((HasTaskChildren)child).getChildren() ), 1);
+    }
+
+    /** the composed effector should allow us to inspect its children */
+    @Test
+    public void testComposedEffectorBasic() throws Exception {
+        Entity txp1 = app.createAndManageChild(EntitySpec.create(Entity.class, Txp1Entity.class));
+        
+        Task<Integer> e = txp1.invoke(TWO_X_PLUS_ONE_BASIC, MutableMap.of("numberToStartWith", 3));
+        Assert.assertTrue(e instanceof DynamicSequentialTask);
+        Assert.assertEquals(e.get(), (Integer)7);
+        Assert.assertEquals( Iterables.size( ((HasTaskChildren)e).getChildren() ), 2);
+    }
+
+    // --------- defining 
+    
+    @Test
+    public void testEffectorWithBodyWorksEvenIfNotOnEntity() throws Exception {
+        Entity doubler = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        
+        Assert.assertEquals(doubler.invoke(DOUBLE_1, MutableMap.of("numberToDouble", 3)).get(), (Integer)6);
+    }
+
+    public static final Effector<Integer> DOUBLE_BODYLESS = Effectors.effector(Integer.class, "double")
+            .description("doubles the given number")
+            .parameter(Integer.class, "numberToDouble")
+            .buildAbstract();
+    
+    @Test
+    public void testEffectorWithoutBodyFails() throws Exception {
+        Entity doubler = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        
+        boolean failed = false;
+        try {
+            doubler.invoke(DOUBLE_BODYLESS, MutableMap.of("numberToDouble", 3));
+        } catch (Exception e) {
+            failed = true;
+        }
+        if (!failed) Assert.fail("doubling should have failed because it had no body");
+    }
+
+    @Test
+    public void testEffectorBodyAdded() throws Exception {
+        EntityInternal doubler = (EntityInternal) app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        
+        // not yet present
+        Assert.assertNull( doubler.getEffector("double") );
+        
+        // add it
+        doubler.getMutableEntityType().addEffector(DOUBLE_BODYLESS, new EffectorBody<Integer>() {
+            @Override
+            public Integer call(ConfigBag parameters) {
+                int input = (Integer)parameters.getStringKey("numberToDouble");
+                return queue(times(input, 2)).getUnchecked();            
+            }
+        });
+        // now it is present
+        Assert.assertNotNull( doubler.getEffector("double") );
+        
+        Assert.assertEquals(doubler.invoke(DOUBLE_BODYLESS, MutableMap.of("numberToDouble", 3)).get(), (Integer)6);
+    }
+
+    @Test
+    public void testEffectorBodyAddedImplicitlyButBodylessSignatureInvoked() throws Exception {
+        EntityInternal doubler = (EntityInternal) app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        
+        // add it
+        doubler.getMutableEntityType().addEffector(DOUBLE_1);
+
+        // invoke it, but using something with equivalent name (and signature -- though only name is used currently)
+        // ensures that the call picks up the body by looking in the actual entity
+        Assert.assertEquals(doubler.invoke(DOUBLE_BODYLESS, MutableMap.of("numberToDouble", 3)).get(), (Integer)6);
+    }
+ 
+    @Test(dependsOnMethods={"testEffectorBodyAdded"})
+    public void testEntityNotPermanentlyChanged() throws Exception {
+        EntityInternal doubler = (EntityInternal) app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        // ensures that independent creations of the class previously modified do not have this effector 
+        Assert.assertNull( doubler.getEffector("double") );
+   }
+    
+    // --- overriding by using statics ---------
+
+    public static class BadDoublingEntity extends DoublingEntity {
+        public static final Effector<Integer> DOUBLE = Effectors.effector(DoublingEntity.DOUBLE).
+                impl( ((EffectorWithBody<Integer>)TWO_X_PLUS_ONE).getBody() ).build();
+    }
+
+    @Test
+    // also assert it works when the entity is defined on an entity
+    public void testOverriddenEffectorOnEntity() throws Exception {
+        Entity doubler = app.createAndManageChild(EntitySpec.create(Entity.class, BadDoublingEntity.class));
+        
+        Assert.assertEquals(doubler.invoke(DoublingEntity.DOUBLE, MutableMap.of("numberToDouble", 3, "numberToStartWith", 3)).get(), (Integer)7);
+    }
+    
+    public static final Effector<Void> DUMMY = Effectors.effector(Void.class, "dummy")
+            .impl(new EffectorBody<Void>() {
+                @Override
+                public Void call(ConfigBag parameters) {
+                    return null;
+                }
+            })
+            .build();
+    
+    public static final Effector<Void> STALL = Effectors.effector(Void.class, "stall")
+            .parameter(AtomicBoolean.class, "lock")
+            .impl(new EffectorBody<Void>() {
+                @Override
+                public Void call(ConfigBag parameters) {
+                    AtomicBoolean lock = (AtomicBoolean)parameters.getStringKey("lock");
+                    synchronized(lock) {
+                        if (!lock.get()) {
+                            try {
+                                lock.wait();
+                            } catch (InterruptedException e) {
+                                Exceptions.propagate(e);
+                            }
+                        }
+                    }
+                    return null;
+                }
+            })
+            .build();
+
+    public static final Effector<Void> CONTEXT = Effectors.effector(Void.class, "stall_caller")
+            .parameter(AtomicBoolean.class, "lock")
+            .impl(new EffectorBody<Void>() {
+                @Override
+                public Void call(ConfigBag parameters) {
+                    Entity child = Iterables.getOnlyElement(entity().getChildren());
+                    AtomicBoolean lock = new AtomicBoolean();
+                    Task<Void> dummyTask = null;
+
+                    try {
+                        // Queue a (DST secondary) task which waits until notified, so that tasks queued later will get blocked
+                        queue(Effectors.invocation(entity(), STALL, ImmutableMap.of("lock", lock)));
+    
+                        // Start a new task - submitted directly to child's ExecutionContext, as well as added as a
+                        // DST secondary of the current effector.
+                        dummyTask = child.invoke(DUMMY, ImmutableMap.<String, Object>of());
+                        dummyTask.getUnchecked();
+
+                        // Execution completed in the child's ExecutionContext, but still queued as a secondary.
+                        // Destroy the child entity so that no subsequent tasks can be executed in its context.
+                        Entities.destroy(child);
+                    } finally {
+                        // Let STALL complete
+                        synchronized(lock) {
+                            lock.set(true);
+                            lock.notifyAll();
+                        }
+                        // At this point DUMMY will be unblocked and the DST will try to execute it as a secondary.
+                        // Submission will be ignored because DUMMY already executed.
+                        // If it's not ignored then submission will fail because entity is already unmanaged.
+                    }
+                    return null;
+                }
+            })
+            .build();
+    
+
+    @Test
+    public void testNestedEffectorExecutedAsSecondaryTask() throws Exception {
+        app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        Task<Void> effTask = app.invoke(CONTEXT, ImmutableMap.<String, Object>of());
+        effTask.get();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/core/effector/ssh/SshEffectorTasksTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/ssh/SshEffectorTasksTest.java b/core/src/test/java/org/apache/brooklyn/core/effector/ssh/SshEffectorTasksTest.java
new file mode 100644
index 0000000..fce676a
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/ssh/SshEffectorTasksTest.java
@@ -0,0 +1,265 @@
+/*
+ * 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.core.effector.ssh;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.mgmt.TaskAdaptable;
+import org.apache.brooklyn.api.mgmt.TaskFactory;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasksTest;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.util.core.task.ssh.SshFetchTaskWrapper;
+import org.apache.brooklyn.util.core.task.ssh.SshPutTaskWrapper;
+import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.util.exceptions.PropagatedRuntimeException;
+import org.apache.brooklyn.util.net.Urls;
+import org.apache.commons.io.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+
+import com.google.common.io.Files;
+
+public class SshEffectorTasksTest {
+
+    private static final Logger log = LoggerFactory.getLogger(SshEffectorTasksTest.class);
+    
+    TestApplication app;
+    ManagementContext mgmt;
+    SshMachineLocation host;
+    File tempDir;
+    
+    boolean failureExpected;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setup() throws Exception {
+        app = TestApplication.Factory.newManagedInstanceForTests();
+        mgmt = app.getManagementContext();
+        
+        LocalhostMachineProvisioningLocation lhc = mgmt.getLocationManager().createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class));
+        host = lhc.obtain();
+        app.start(Arrays.asList(host));
+        clearExpectedFailure();
+        tempDir = Files.createTempDir();
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (mgmt != null) Entities.destroyAll(mgmt);
+        mgmt = null;
+        FileUtils.deleteDirectory(tempDir);
+        checkExpectedFailure();
+    }
+
+    protected void checkExpectedFailure() {
+        if (failureExpected) {
+            clearExpectedFailure();
+            Assert.fail("Test should have thrown an exception but it did not.");
+        }
+    }
+    
+    protected void clearExpectedFailure() {
+        failureExpected = false;
+    }
+
+    protected void setExpectingFailure() {
+        failureExpected = true;
+    }
+    
+    public <T extends TaskAdaptable<?>> T submit(final TaskFactory<T> taskFactory) {
+        return Entities.submit(app, taskFactory);
+    }
+    
+    // ------------------- basic ssh
+    
+    @Test(groups="Integration")
+    public void testSshEchoHello() {
+        ProcessTaskWrapper<Integer> t = submit(SshEffectorTasks.ssh("sleep 1 ; echo hello world"));
+        Assert.assertFalse(t.isDone());
+        Assert.assertEquals(t.get(), (Integer)0);
+        Assert.assertEquals(t.getTask().getUnchecked(), (Integer)0);
+        Assert.assertEquals(t.getStdout().trim(), "hello world");
+    }
+
+    @Test(groups="Integration")
+    public void testSshPut() throws IOException {
+        String fn = Urls.mergePaths(tempDir.getPath(), "f1");
+        SshPutTaskWrapper t = submit(SshEffectorTasks.put(fn).contents("hello world"));
+        t.block();
+        Assert.assertEquals(FileUtils.readFileToString(new File(fn)), "hello world");
+        // and make sure this doesn't throw
+        Assert.assertTrue(t.isDone());
+        Assert.assertTrue(t.isSuccessful());
+        Assert.assertEquals(t.get(), null);
+        Assert.assertEquals(t.getExitCode(), (Integer)0);
+    }
+
+    @Test(groups="Integration")
+    public void testSshFetch() throws IOException {
+        String fn = Urls.mergePaths(tempDir.getPath(), "f2");
+        FileUtils.write(new File(fn), "hello fetched world");
+        
+        SshFetchTaskWrapper t = submit(SshEffectorTasks.fetch(fn));
+        t.block();
+        
+        Assert.assertTrue(t.isDone());
+        Assert.assertEquals(t.get(), "hello fetched world");
+    }
+
+    // ----------------- pid stuff
+    
+    @Test(groups="Integration")
+    public void testNonRunningPid() {
+        ProcessTaskWrapper<Integer> t = submit(SshEffectorTasks.codePidRunning(99999));
+        Assert.assertNotEquals(t.getTask().getUnchecked(), (Integer)0);
+        Assert.assertNotEquals(t.getExitCode(), (Integer)0);
+        ProcessTaskWrapper<Boolean> t2 = submit(SshEffectorTasks.isPidRunning(99999));
+        Assert.assertFalse(t2.getTask().getUnchecked());
+    }
+
+    @Test(groups="Integration")
+    public void testNonRunningPidRequired() {
+        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidRunning(99999));
+        setExpectingFailure();
+        try {
+            t.getTask().getUnchecked();
+        } catch (Exception e) {
+            log.info("The error if required PID is not found is: "+e);
+            clearExpectedFailure();
+            Assert.assertTrue(e.toString().contains("Process with PID"), "Expected nice clue in error but got: "+e);
+        }
+        checkExpectedFailure();
+    }
+
+    public static Integer getMyPid() {
+        try {
+            java.lang.management.RuntimeMXBean runtime = 
+                    java.lang.management.ManagementFactory.getRuntimeMXBean();
+            java.lang.reflect.Field jvm = runtime.getClass().getDeclaredField("jvm");
+            jvm.setAccessible(true);
+//            sun.management.VMManagement mgmt = (sun.management.VMManagement) jvm.get(runtime);
+            Object mgmt = jvm.get(runtime);
+            java.lang.reflect.Method pid_method =  
+                    mgmt.getClass().getDeclaredMethod("getProcessId");
+            pid_method.setAccessible(true);
+
+            return (Integer) pid_method.invoke(mgmt);
+        } catch (Exception e) {
+            throw new PropagatedRuntimeException("Test depends on (fragile) getMyPid method which does not work here", e);
+        }
+    }
+
+    @Test(groups="Integration")
+    public void testRunningPid() {
+        ProcessTaskWrapper<Integer> t = submit(SshEffectorTasks.codePidRunning(getMyPid()));
+        Assert.assertEquals(t.getTask().getUnchecked(), (Integer)0);
+        ProcessTaskWrapper<Boolean> t2 = submit(SshEffectorTasks.isPidRunning(getMyPid()));
+        Assert.assertTrue(t2.getTask().getUnchecked());
+    }
+
+    @Test(groups="Integration")
+    public void testRunningPidFromFile() throws IOException {
+        File f = File.createTempFile("testBrooklynPid", ".pid");
+        Files.write( (""+getMyPid()).getBytes(), f );
+        ProcessTaskWrapper<Integer> t = submit(SshEffectorTasks.codePidFromFileRunning(f.getPath()));
+        Assert.assertEquals(t.getTask().getUnchecked(), (Integer)0);
+        ProcessTaskWrapper<Boolean> t2 = submit(SshEffectorTasks.isPidFromFileRunning(f.getPath()));
+        Assert.assertTrue(t2.getTask().getUnchecked());
+    }
+
+    @Test(groups="Integration")
+    public void testRequirePidFromFileOnFailure() throws IOException {
+        File f = File.createTempFile("testBrooklynPid", ".pid");
+        Files.write( "99999".getBytes(), f );
+        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidFromFileRunning(f.getPath()));
+        
+        setExpectingFailure();
+        try {
+            t.getTask().getUnchecked();
+        } catch (Exception e) {
+            log.info("The error if required PID is not found is: "+e);
+            clearExpectedFailure();
+            Assert.assertTrue(e.toString().contains("Process with PID"), "Expected nice clue in error but got: "+e);
+            Assert.assertEquals(t.getExitCode(), (Integer)1);
+        }
+        checkExpectedFailure();
+    }
+
+    @Test(groups="Integration")
+    public void testRequirePidFromFileOnFailureNoSuchFile() throws IOException {
+        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidFromFileRunning("/path/does/not/exist/SADVQW"));
+        
+        setExpectingFailure();
+        try {
+            t.getTask().getUnchecked();
+        } catch (Exception e) {
+            log.info("The error if required PID is not found is: "+e);
+            clearExpectedFailure();
+            Assert.assertTrue(e.toString().contains("Process with PID"), "Expected nice clue in error but got: "+e);
+            Assert.assertEquals(t.getExitCode(), (Integer)1);
+        }
+        checkExpectedFailure();
+    }
+
+    @Test(groups="Integration")
+    public void testRequirePidFromFileOnFailureTooManyFiles() throws IOException {
+        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidFromFileRunning("/*"));
+        
+        setExpectingFailure();
+        try {
+            t.getTask().getUnchecked();
+        } catch (Exception e) {
+            log.info("The error if required PID is not found is: "+e);
+            clearExpectedFailure();
+            Assert.assertTrue(e.toString().contains("Process with PID"), "Expected nice clue in error but got: "+e);
+            Assert.assertEquals(t.getExitCode(), (Integer)2);
+        }
+        checkExpectedFailure();
+    }
+
+    @Test(groups="Integration")
+    public void testRequirePidFromFileOnSuccess() throws IOException {
+        File f = File.createTempFile("testBrooklynPid", ".pid");
+        Files.write( (""+getMyPid()).getBytes(), f );
+        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidFromFileRunning(f.getPath()));
+        
+        t.getTask().getUnchecked();
+    }
+
+    @Test(groups="Integration")
+    public void testRequirePidFromFileOnSuccessAcceptsWildcards() throws IOException {
+        File f = File.createTempFile("testBrooklynPid", ".pid");
+        Files.write( (""+getMyPid()).getBytes(), f );
+        ProcessTaskWrapper<?> t = submit(SshEffectorTasks.requirePidFromFileRunning(f.getPath()+"*"));
+        
+        t.getTask().getUnchecked();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/core/entity/DynamicEntityTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/DynamicEntityTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/DynamicEntityTest.java
index 885eb45..fb9276c 100644
--- a/core/src/test/java/org/apache/brooklyn/core/entity/DynamicEntityTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/DynamicEntityTest.java
@@ -24,10 +24,10 @@ import static org.testng.Assert.assertFalse;
 import org.apache.brooklyn.api.entity.EntityInitializer;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.effector.EffectorTaskTest;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.effector.core.EffectorTaskTest;
 import org.apache.brooklyn.entity.stock.BasicEntity;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.testng.annotations.Test;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/core/entity/EntityTypeTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/EntityTypeTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/EntityTypeTest.java
index c01c5c9..cead05a 100644
--- a/core/src/test/java/org/apache/brooklyn/core/entity/EntityTypeTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/EntityTypeTest.java
@@ -47,13 +47,13 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.core.test.entity.TestEntityImpl;
-import org.apache.brooklyn.effector.core.MethodEffector;
 import org.apache.brooklyn.sensor.core.BasicSensorEvent;
 import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.test.Asserts;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/core/entity/hello/HelloEntity.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/hello/HelloEntity.java b/core/src/test/java/org/apache/brooklyn/core/entity/hello/HelloEntity.java
index 9d14868..a217514 100644
--- a/core/src/test/java/org/apache/brooklyn/core/entity/hello/HelloEntity.java
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/hello/HelloEntity.java
@@ -25,7 +25,7 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.annotation.EffectorParam;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.effector.core.MethodEffector;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.entity.group.AbstractGroup;
 import org.apache.brooklyn.sensor.core.BasicSensor;
 import org.apache.brooklyn.sensor.core.Sensors;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiVersionMoreEntityTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiVersionMoreEntityTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiVersionMoreEntityTest.java
index f648419..1d50609 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiVersionMoreEntityTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiVersionMoreEntityTest.java
@@ -42,6 +42,7 @@ import org.apache.brooklyn.core.catalog.internal.CatalogItemBuilder;
 import org.apache.brooklyn.core.catalog.internal.CatalogItemDtoAbstract;
 import org.apache.brooklyn.core.catalog.internal.CatalogTestUtils;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext;
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
@@ -50,7 +51,6 @@ import org.apache.brooklyn.core.objs.proxy.InternalEntityFactory;
 import org.apache.brooklyn.core.objs.proxy.InternalPolicyFactory;
 import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.test.support.TestResourceUnavailableException;
 import org.apache.brooklyn.util.core.osgi.Osgis;
 import org.apache.brooklyn.util.guava.Maybe;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEntityDynamicTypeInfoTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEntityDynamicTypeInfoTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEntityDynamicTypeInfoTest.java
index c25dd0e..3b9bbfb 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEntityDynamicTypeInfoTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEntityDynamicTypeInfoTest.java
@@ -29,10 +29,10 @@ import org.apache.brooklyn.api.effector.Effector;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.EffectorBody;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.effector.core.EffectorBody;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.stream.Streams;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/core/test/entity/TestEntity.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/test/entity/TestEntity.java b/core/src/test/java/org/apache/brooklyn/core/test/entity/TestEntity.java
index 2106f18..8c185a0 100644
--- a/core/src/test/java/org/apache/brooklyn/core/test/entity/TestEntity.java
+++ b/core/src/test/java/org/apache/brooklyn/core/test/entity/TestEntity.java
@@ -36,11 +36,11 @@ import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.config.ListConfigKey;
 import org.apache.brooklyn.core.config.MapConfigKey;
 import org.apache.brooklyn.core.config.SetConfigKey;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.effector.core.MethodEffector;
 import org.apache.brooklyn.sensor.core.BasicNotificationSensor;
 import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.collections.MutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/effector/core/EffectorBasicTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/effector/core/EffectorBasicTest.java b/core/src/test/java/org/apache/brooklyn/effector/core/EffectorBasicTest.java
deleted file mode 100644
index 786fe69..0000000
--- a/core/src/test/java/org/apache/brooklyn/effector/core/EffectorBasicTest.java
+++ /dev/null
@@ -1,183 +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.effector.core;
-
-import java.util.List;
-import java.util.concurrent.Callable;
-
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.mgmt.HasTaskChildren;
-import org.apache.brooklyn.api.mgmt.Task;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.trait.FailingEntity;
-import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.core.location.SimulatedLocation;
-import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
-import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.test.TestUtils;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.ImmutableList;
-
-public class EffectorBasicTest extends BrooklynAppUnitTestSupport {
-
-    private static final Logger log = LoggerFactory.getLogger(EffectorBasicTest.class);
-    
-    // NB: more tests of effectors in EffectorSayHiTest and EffectorConcatenateTest
-    // as well as EntityConfigMapUsageTest and others
-
-    private List<SimulatedLocation> locs;
-    
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        locs = ImmutableList.of(new SimulatedLocation());
-    }
-    
-    @Test
-    public void testInvokeEffectorStart() {
-        app.start(locs);
-        TestUtils.assertSetsEqual(locs, app.getLocations());
-        // TODO above does not get registered as a task
-    }
-
-    @Test
-    public void testInvokeEffectorStartWithMap() {
-        app.invoke(Startable.START, MutableMap.of("locations", locs)).getUnchecked();
-        TestUtils.assertSetsEqual(locs, app.getLocations());
-    }
-
-    @Test
-    public void testInvokeEffectorStartWithArgs() {
-        Entities.invokeEffectorWithArgs((EntityLocal)app, app, Startable.START, locs).getUnchecked();
-        TestUtils.assertSetsEqual(locs, app.getLocations());
-    }
-
-    @Test
-    public void testInvokeEffectorStartWithTwoEntities() {
-        TestEntity entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        TestEntity entity2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        app.start(locs);
-        TestUtils.assertSetsEqual(locs, app.getLocations());
-        TestUtils.assertSetsEqual(locs, entity.getLocations());
-        TestUtils.assertSetsEqual(locs, entity2.getLocations());
-    }
-    
-    @Test
-    public void testInvokeEffectorTaskHasTag() {
-        Task<Void> starting = app.invoke(Startable.START, MutableMap.of("locations", locs));
-//        log.info("TAGS: "+starting.getTags());
-        Assert.assertTrue(starting.getTags().contains(ManagementContextInternal.EFFECTOR_TAG));
-    }
-
-    // check various failure situations
-    
-    private FailingEntity createFailingEntity() {
-        FailingEntity entity = app.createAndManageChild(EntitySpec.create(FailingEntity.class)
-            .configure(FailingEntity.FAIL_ON_START, true));
-        return entity;
-    }
-
-    // uncaught failures are propagates
-    
-    @Test
-    public void testInvokeEffectorStartFailing_Method() {
-        FailingEntity entity = createFailingEntity();
-        assertStartMethodFails(entity);
-    }
-
-    @Test
-    public void testInvokeEffectorStartFailing_EntityInvoke() {
-        FailingEntity entity = createFailingEntity();
-        assertTaskFails( entity.invoke(Startable.START, MutableMap.of("locations", locs)) );
-    }
-     
-    @Test
-    public void testInvokeEffectorStartFailing_EntitiesInvoke() {
-        FailingEntity entity = createFailingEntity();
-        
-        assertTaskFails( Entities.invokeEffectorWithArgs(entity, entity, Startable.START, locs) );
-    }
-
-    // caught failures are NOT propagated!
-    
-    @Test
-    public void testInvokeEffectorStartFailing_MethodInDynamicTask() {
-        Task<Void> task = app.getExecutionContext().submit(Tasks.<Void>builder().dynamic(true).body(new Callable<Void>() {
-            @Override public Void call() throws Exception {
-                testInvokeEffectorStartFailing_Method();
-                return null;
-            }
-        }).build());
-        
-        assertTaskSucceeds(task);
-        assertTaskHasFailedChild(task);
-    }
-
-    @Test
-    public void testInvokeEffectorStartFailing_MethodInTask() {
-        Task<Void> task = app.getExecutionContext().submit(Tasks.<Void>builder().dynamic(false).body(new Callable<Void>() {
-            @Override public Void call() throws Exception {
-                testInvokeEffectorStartFailing_Method();
-                return null;
-            }
-        }).build());
-        
-        assertTaskSucceeds(task);
-    }
-
-    private void assertTaskSucceeds(Task<Void> task) {
-        task.getUnchecked();
-        Assert.assertFalse(task.isError());
-    }
-
-    private void assertTaskHasFailedChild(Task<Void> task) {
-        Assert.assertTrue(Tasks.failed( ((HasTaskChildren)task).getChildren() ).iterator().hasNext());
-    }
-        
-    private void assertStartMethodFails(FailingEntity entity) {
-        try {
-            entity.start(locs);
-            Assert.fail("Should have failed");
-        } catch (Exception e) {
-            // expected
-        }
-    }
-     
-    protected void assertTaskFails(Task<?> t) {
-        try {
-            t.get();
-            Assert.fail("Should have failed");
-        } catch (Exception e) {
-            Exceptions.propagateIfFatal(e);
-            // expected
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/effector/core/EffectorConcatenateTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/effector/core/EffectorConcatenateTest.java b/core/src/test/java/org/apache/brooklyn/effector/core/EffectorConcatenateTest.java
deleted file mode 100644
index 9372e41..0000000
--- a/core/src/test/java/org/apache/brooklyn/effector/core/EffectorConcatenateTest.java
+++ /dev/null
@@ -1,241 +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.effector.core;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.fail;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.mgmt.ExecutionManager;
-import org.apache.brooklyn.api.mgmt.Task;
-import org.apache.brooklyn.core.annotation.Effector;
-import org.apache.brooklyn.core.annotation.EffectorParam;
-import org.apache.brooklyn.core.entity.AbstractEntity;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.apache.brooklyn.core.test.entity.TestApplicationImpl;
-import org.apache.brooklyn.effector.core.MethodEffector;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.task.BasicExecutionContext;
-import org.apache.brooklyn.util.core.task.Tasks;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-
-public class EffectorConcatenateTest {
-
-    
-    private static final Logger log = LoggerFactory.getLogger(EffectorConcatenateTest.class);
-    private static final long TIMEOUT = 10*1000;
-    
-    public static class MyEntityImpl extends AbstractEntity {
-
-        public static MethodEffector<String> CONCATENATE = new MethodEffector<String>(MyEntityImpl.class, "concatenate");
-        public static MethodEffector<Void> WAIT_A_BIT = new MethodEffector<Void>(MyEntityImpl.class, "waitabit");
-        public static MethodEffector<Void> SPAWN_CHILD = new MethodEffector<Void>(MyEntityImpl.class, "spawnchild");
-
-        public MyEntityImpl() {
-            super();
-        }
-        public MyEntityImpl(Entity parent) {
-            super(parent);
-        }
-
-        /** The "current task" representing the effector currently executing */
-        AtomicReference<Task<?>> waitingTask = new AtomicReference<Task<?>>();
-        
-        /** latch is .countDown'ed by the effector at the beginning of the "waiting" point */
-        CountDownLatch nowWaitingLatch = new CountDownLatch(1);
-        
-        /** latch is await'ed on by the effector when it is in the "waiting" point */
-        CountDownLatch continueFromWaitingLatch = new CountDownLatch(1);
-        
-        @Effector(description="sample effector concatenating strings")
-        public String concatenate(@EffectorParam(name="first", description="first argument") String first,
-                @EffectorParam(name="second", description="2nd arg") String second) throws Exception {
-            return first+second;
-        }
-        
-        @Effector(description="sample effector doing some waiting")
-        public void waitabit() throws Exception {
-            waitingTask.set(Tasks.current());
-            
-            Tasks.setExtraStatusDetails("waitabit extra status details");
-            
-            Tasks.withBlockingDetails("waitabit.blocking", new Callable<Void>() {
-                    public Void call() throws Exception {
-                        nowWaitingLatch.countDown();
-                        if (!continueFromWaitingLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
-                            fail("took too long to be told to continue");
-                        }
-                        return null;
-                    }});
-        }
-        
-        @Effector(description="sample effector that spawns a child task that waits a bit")
-        public void spawnchild() throws Exception {
-            // spawn a child, then wait
-            BasicExecutionContext.getCurrentExecutionContext().submit(
-                    MutableMap.of("displayName", "SpawnedChildName"),
-                    new Callable<Void>() {
-                        public Void call() throws Exception {
-                            log.info("beginning spawned child response "+Tasks.current()+", with tags "+Tasks.current().getTags());
-                            Tasks.setBlockingDetails("spawned child blocking details");
-                            nowWaitingLatch.countDown();
-                            if (!continueFromWaitingLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
-                                fail("took too long to be told to continue");
-                            }
-                            return null;
-                        }});
-        }
-    }
-            
-    private TestApplication app;
-    private MyEntityImpl e;
-    
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() {
-        app = new TestApplicationImpl();
-        e = new MyEntityImpl(app);
-        Entities.startManagement(app);
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() {
-        if (app != null) Entities.destroyAll(app.getManagementContext());
-    }
-    
-    @Test
-    public void testCanInvokeEffector() throws Exception {
-        // invocation map syntax
-        Task<String> task = e.invoke(MyEntityImpl.CONCATENATE, ImmutableMap.of("first", "a", "second", "b"));
-        assertEquals(task.get(TIMEOUT, TimeUnit.MILLISECONDS), "ab");
-
-        // method syntax
-        assertEquals("xy", e.concatenate("x", "y"));
-    }
-    
-    @Test
-    public void testReportsTaskDetails() throws Exception {
-        final AtomicReference<String> result = new AtomicReference<String>();
-
-        Thread bg = new Thread(new Runnable() {
-            public void run() {
-                try {
-                    // Expect "wait a bit" to tell us it's blocking 
-                    if (!e.nowWaitingLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
-                        result.set("took too long for waitabit to be waiting");
-                        return;
-                    }
-
-                    // Expect "wait a bit" to have retrieved and set its task
-                    try {
-                        Task<?> t = e.waitingTask.get();
-                        String status = t.getStatusDetail(true);
-                        log.info("waitabit task says:\n"+status);
-                        if (!status.contains("waitabit extra status details")) {
-                            result.set("Status not in expected format: doesn't contain extra status details phrase 'My extra status details'\n"+status);
-                            return;
-                        }
-                        if (!status.startsWith("waitabit.blocking")) {
-                            result.set("Status not in expected format: doesn't start with blocking details 'waitabit.blocking'\n"+status);
-                            return;
-                        }
-                    } finally {
-                        e.continueFromWaitingLatch.countDown();
-                    }
-                } catch (Throwable t) {
-                    log.warn("Failure: "+t, t);
-                    result.set("Failure: "+t);
-                }
-            }});
-        bg.start();
-    
-        e.invoke(MyEntityImpl.WAIT_A_BIT, ImmutableMap.<String,Object>of())
-                .get(TIMEOUT, TimeUnit.MILLISECONDS);
-        
-        bg.join(TIMEOUT*2);
-        assertFalse(bg.isAlive());
-        
-        String problem = result.get();
-        if (problem!=null) fail(problem);
-    }
-    
-    @Test
-    public void testReportsSpawnedTaskDetails() throws Exception {
-        final AtomicReference<String> result = new AtomicReference<String>();
-
-        Thread bg = new Thread(new Runnable() {
-            public void run() {
-                try {
-                    // Expect "spawned child" to tell us it's blocking 
-                    if (!e.nowWaitingLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
-                        result.set("took too long for spawnchild's sub-task to be waiting");
-                        return;
-                    }
-
-                    // Expect spawned task to be have been tagged with entity
-                    ExecutionManager em = e.getManagementContext().getExecutionManager();
-                    Task<?> subtask = Iterables.find(BrooklynTaskTags.getTasksInEntityContext(em, e), new Predicate<Task<?>>() {
-                        public boolean apply(Task<?> input) {
-                            return "SpawnedChildName".equals(input.getDisplayName());
-                        }
-                    });
-                    
-                    // Expect spawned task to haev correct "blocking details"
-                    try {
-                        String status = subtask.getStatusDetail(true);
-                        log.info("subtask task says:\n"+status);
-                        if (!status.contains("spawned child blocking details")) {
-                            result.set("Status not in expected format: doesn't contain blocking details phrase 'spawned child blocking details'\n"+status);
-                            return;
-                        }
-                    } finally {
-                        e.continueFromWaitingLatch.countDown();
-                    }
-                } catch (Throwable t) {
-                    log.warn("Failure: "+t, t);
-                    result.set("Failure: "+t);
-                }
-            }});
-        bg.start();
-    
-        e.invoke(MyEntityImpl.SPAWN_CHILD, ImmutableMap.<String,Object>of())
-                .get(TIMEOUT, TimeUnit.MILLISECONDS);
-        
-        bg.join(TIMEOUT*2);
-        assertFalse(bg.isAlive());
-        
-        String problem = result.get();
-        if (problem!=null) fail(problem);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/effector/core/EffectorMetadataTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/effector/core/EffectorMetadataTest.java b/core/src/test/java/org/apache/brooklyn/effector/core/EffectorMetadataTest.java
deleted file mode 100644
index b8b6bf4..0000000
--- a/core/src/test/java/org/apache/brooklyn/effector/core/EffectorMetadataTest.java
+++ /dev/null
@@ -1,166 +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.effector.core;
-
-import static org.testng.Assert.assertEquals;
-
-import java.util.Collection;
-import java.util.List;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.api.effector.ParameterType;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.entity.ImplementedBy;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.core.annotation.EffectorParam;
-import org.apache.brooklyn.core.entity.AbstractEntity;
-import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.core.mgmt.internal.EffectorUtils;
-import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.effector.core.BasicParameterType;
-import org.apache.brooklyn.effector.core.Effectors;
-import org.apache.brooklyn.effector.core.MethodEffector;
-import org.testng.Assert;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.ImmutableList;
-
-/**
- * Test the operation of the {@link Effector} implementations.
- *
- * TODO clarify test purpose
- */
-public class EffectorMetadataTest extends BrooklynAppUnitTestSupport {
-    
-    private MyAnnotatedEntity e1;
-    private MyOverridingEntity e2;
-
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        e1 = app.createAndManageChild(EntitySpec.create(MyAnnotatedEntity.class));
-        e2 = app.createAndManageChild(EntitySpec.create(MyOverridingEntity.class));
-    }
-
-    @Test
-    public void testEffectorMetaDataFromAnnotationsWithConstant() {
-        Effector<?> effector = EffectorUtils.findEffectorDeclared(e1, "effWithNewAnnotation").get();
-        Assert.assertTrue(Effectors.sameSignature(effector, MyAnnotatedEntity.EFF_WITH_NEW_ANNOTATION));
-        assertEquals(effector.getName(), "effWithNewAnnotation");
-        assertEquals(effector.getDescription(), "my effector description");
-        assertEquals(effector.getReturnType(), String.class);
-        assertParametersEqual(
-                effector.getParameters(), 
-                ImmutableList.<ParameterType<?>>of(
-                        new BasicParameterType<String>("param1", String.class, "my param description", "my default val")));
-    }
-
-    @Test
-    public void testEffectorMetaDataFromAnnotationsWithoutConstant() {
-        Effector<?> effector = EffectorUtils.findEffectorDeclared(e1, "effWithAnnotationButNoConstant").get();
-        assertEquals(effector.getName(), "effWithAnnotationButNoConstant");
-        assertEquals(effector.getDescription(), "my effector description");
-        assertEquals(effector.getReturnType(), String.class);
-        assertParametersEqual(
-                effector.getParameters(), 
-                ImmutableList.<ParameterType<?>>of(
-                        new BasicParameterType<String>("param1", String.class, "my param description", "my default val")));
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Test
-    public void testEffectorMetaDataFromOverriddenMethod() {
-        // Overridden with new annotations
-        Effector<?> startEffector = EffectorUtils.findEffectorDeclared(e2, "start").get();
-        assertEquals(startEffector.getName(), "start");
-        assertEquals(startEffector.getDescription(), "My overridden start description");
-        assertEquals(startEffector.getReturnType(), void.class);
-        assertParametersEqual(
-                startEffector.getParameters(), 
-                ImmutableList.<ParameterType<?>>of(
-                        new BasicParameterType<Collection>("locations", Collection.class, "my overridden param description", null)));
-    }
-
-    private void assertParametersEqual(List<ParameterType<?>> actuals, List<ParameterType<?>> expecteds) {
-        assertEquals(actuals.size(), expecteds.size(), "actual="+actuals);
-        for (int i = 0; i < actuals.size(); i++) {
-            ParameterType<?> actual = actuals.get(i);
-            ParameterType<?> expected = expecteds.get(i);
-            assertParameterEqual(actual, expected);
-        }
-    }
-    
-    private void assertParameterEqual(ParameterType<?> actual, ParameterType<?> expected) {
-        assertEquals(actual.getName(), expected.getName(), "actual="+actual);
-        assertEquals(actual.getDescription(), expected.getDescription(), "actual="+actual);
-        assertEquals(actual.getParameterClass(), expected.getParameterClass(), "actual="+actual);
-        assertEquals(actual.getParameterClassName(), expected.getParameterClassName(), "actual="+actual);
-    }
-
-    @ImplementedBy(MyAnnotatedEntityImpl.class)
-    public interface MyAnnotatedEntity extends Entity {
-        static MethodEffector<String> EFF_WITH_NEW_ANNOTATION = new MethodEffector<String>(MyAnnotatedEntity.class, "effWithNewAnnotation");
-
-        @org.apache.brooklyn.core.annotation.Effector(description="my effector description")
-        public String effWithNewAnnotation(
-                @EffectorParam(name="param1", defaultValue="my default val", description="my param description") String param1);
-        
-        @org.apache.brooklyn.core.annotation.Effector(description="my effector description")
-        public String effWithAnnotationButNoConstant(
-                @EffectorParam(name="param1", defaultValue="my default val", description="my param description") String param1);
-    }
-    
-    public static class MyAnnotatedEntityImpl extends AbstractEntity implements MyAnnotatedEntity {
-        @Override
-        public String effWithNewAnnotation(String param1) {
-            return param1;
-        }
-
-        @Override
-        public String effWithAnnotationButNoConstant(String param1) {
-            return param1;
-        }
-    }
-    
-    @ImplementedBy(MyOverridingEntityImpl.class)
-    public interface MyOverridingEntity extends Entity, Startable {
-        org.apache.brooklyn.api.effector.Effector<Void> START = Effectors.effector(Startable.START)
-            .description("My overridden start description")
-            .parameter(Collection.class, "locations", "my overridden param description")
-            .build();
-    }
-
-    public static class MyOverridingEntityImpl extends AbstractEntity implements MyOverridingEntity {
-
-        @Override
-        public void restart() {
-        }
-
-        @Override
-        public void start(Collection<? extends Location> locations2) {
-        }
-
-        @Override
-        public void stop() {
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/effector/core/EffectorSayHiGroovyTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/effector/core/EffectorSayHiGroovyTest.groovy b/core/src/test/java/org/apache/brooklyn/effector/core/EffectorSayHiGroovyTest.groovy
deleted file mode 100644
index ec5c442..0000000
--- a/core/src/test/java/org/apache/brooklyn/effector/core/EffectorSayHiGroovyTest.groovy
+++ /dev/null
@@ -1,179 +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.effector.core
-
-import static org.testng.Assert.*
-
-import org.apache.brooklyn.api.effector.Effector
-import org.apache.brooklyn.api.entity.Entity
-import org.apache.brooklyn.api.entity.EntitySpec
-import org.apache.brooklyn.api.entity.ImplementedBy
-import org.apache.brooklyn.api.mgmt.ManagementContext
-import org.apache.brooklyn.api.mgmt.Task
-import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.core.mgmt.internal.EffectorUtils
-import org.apache.brooklyn.core.test.entity.TestApplication
-import org.apache.brooklyn.core.annotation.EffectorParam
-import org.apache.brooklyn.core.entity.AbstractEntity
-import org.apache.brooklyn.core.entity.Entities
-import org.apache.brooklyn.core.entity.trait.Startable
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import org.testng.annotations.AfterMethod
-import org.testng.annotations.BeforeMethod
-import org.testng.annotations.Test
-
-/**
- * Test the operation of the {@link Effector} implementations.
- *
- * TODO clarify test purpose
- */
-public class EffectorSayHiGroovyTest {
-    private static final Logger log = LoggerFactory.getLogger(EffectorSayHiTest.class);
-
-    private TestApplication app;
-    private MyEntity e;
-
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() {
-        app = TestApplication.Factory.newManagedInstanceForTests();
-        e = app.createAndManageChild(EntitySpec.create(MyEntity.class));
-    }
-
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() {
-        if (app != null) Entities.destroyAll(app.getManagementContext());
-    }
-
-    @Test
-    public void testFindEffectors() {
-        assertEquals("sayHi1", e.SAY_HI_1.getName());
-        assertEquals(["name", "greeting"], e.SAY_HI_1.getParameters()[0..1]*.getName());
-        assertEquals("says hello", e.SAY_HI_1.getDescription());
-
-		assertEquals("sayHi1", e.SAY_HI_1_ALT.getName());
-		assertEquals(["name", "greeting"], e.SAY_HI_1_ALT.getParameters()[0..1]*.getName());
-		assertEquals("says hello", e.SAY_HI_1_ALT.getDescription());
-
-		assertEquals("sayHi2", e.SAY_HI_2.getName());
-		assertEquals(["name", "greeting"], e.SAY_HI_2.getParameters()[0..1]*.getName());
-		assertEquals("says hello", e.SAY_HI_2.getDescription());
-    }
-
-    @Test
-    public void testFindTraitEffectors() {
-        assertEquals("locations", Startable.START.getParameters()[0].getName());
-    }
-
-    @Test
-    public void testInvokeEffectorMethod1BypassInterception() {
-        String name = "sayHi1"
-        def args = ["Bob", "hello"] as Object[]
-
-        //try the alt syntax recommended from web
-        def metaMethod = e.metaClass.getMetaMethod(name, args)
-        if (metaMethod==null)
-            throw new IllegalArgumentException("Invalid arguments (no method found) for method $name: "+args);
-        assertEquals("hello Bob", metaMethod.invoke(e, args))
-    }
-
-    @Test
-    public void testInvokeEffectorMethod2BypassInterception() {
-        String name = "sayHi2"
-        def args = ["Bob", "hello"] as Object[]
-        assertEquals("hello Bob", e.metaClass.invokeMethod(e, name, args))
-    }
-
-    @Test
-    public void testInvokeEffectors1() {
-        assertEquals("hi Bob", e.sayHi1("Bob", "hi"))
-
-        assertEquals("hello Bob", e.SAY_HI_1.call(e, [name:"Bob"]) )
-        assertEquals("hello Bob", e.invoke(e.SAY_HI_1, [name:"Bob"]).get() );
-
-		assertEquals("hello Bob", e.SAY_HI_1_ALT.call(e, [name:"Bob"]) )
-    }
-
-    @Test
-    public void testInvokeEffectors2() {
-        assertEquals("hi Bob", e.sayHi2("Bob", "hi"))
-
-        assertEquals("hello Bob", e.SAY_HI_2.call(e, [name:"Bob"]) )
-        assertEquals("hello Bob", e.invoke(e.SAY_HI_2, [name:"Bob"]).get() );
-        
-    }
-
-    @Test
-    public void testCanRetrieveTaskForEffector() {
-        e.sayHi2("Bob", "hi")
-
-        ManagementContext managementContext = e.getManagementContext()
-
-        Set<Task> tasks = managementContext.getExecutionManager().getTasksWithAllTags([
-            BrooklynTaskTags.tagForContextEntity(e),"EFFECTOR"])
-        assertEquals(tasks.size(), 1)
-        assertTrue(tasks.iterator().next().getDescription().contains("sayHi2"))
-    }
-}
-public interface CanSayHi {
-	//prefer following simple groovy syntax
-	static Effector<String> SAY_HI_1 = new MethodEffector<String>(CanSayHi.&sayHi1);
-	//slightly longer-winded pojo also supported
-	static Effector<String> SAY_HI_1_ALT = new MethodEffector<String>(CanSayHi.class, "sayHi1");
-
-	@org.apache.brooklyn.core.annotation.Effector(description="says hello")
-	public String sayHi1(
-		@EffectorParam(name="name") String name,
-		@EffectorParam(name="greeting", defaultValue="hello", description="what to say") String greeting);
-
-	//finally there is a way to provide a class/closure if needed or preferred for some odd reason
-	static Effector<String> SAY_HI_2 =
-
-		//groovy 1.8.2 balks at runtime during getCallSiteArray (bug 5122) if we use anonymous inner class
-//	  new ExplicitEffector<CanSayHi,String>(
-//			"sayHi2", String.class, [
-//					[ "name", String.class, "person to say hi to" ] as BasicParameterType<String>,
-//					[ "greeting", String.class, "what to say as greeting", "hello" ] as BasicParameterType<String>
-//				],
-//			"says hello to a person") {
-//		public String invokeEffector(CanSayHi e, Map m) {
-//			e.sayHi2(m)
-//		}
-//	};
-	//following is a workaround, not greatly enamoured of it... but MethodEffector is generally preferred anyway
-		ExplicitEffector.create("sayHi2", String.class, [
-					new BasicParameterType<String>("name", String.class, "person to say hi to"),
-					new BasicParameterType<String>("greeting", String.class, "what to say as greeting", "hello")
-				],
-			"says hello", { e, m ->
-                def args = EffectorUtils.prepareArgsForEffector(SAY_HI_2, m);
-                e.sayHi2(args[0], args[1]) })
-
-	public String sayHi2(String name, String greeting);
-
-}
-
-@ImplementedBy(MyEntityImpl.class)
-public interface MyEntity extends Entity, CanSayHi {
-}
-
-public class MyEntityImpl extends AbstractEntity implements MyEntity {
-    public String sayHi1(String name, String greeting) { "$greeting $name" }
-	public String sayHi2(String name, String greeting) { "$greeting $name" }
-}


[02/36] incubator-brooklyn git commit: Move SshEffectorTasks into core’s effector.ssh package

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/mysql/AbstractToyMySqlEntityTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/mysql/AbstractToyMySqlEntityTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/mysql/AbstractToyMySqlEntityTest.java
index f2ab43c..82fd74f 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/mysql/AbstractToyMySqlEntityTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/mysql/AbstractToyMySqlEntityTest.java
@@ -25,10 +25,10 @@ import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.util.time.Duration;
 import org.apache.brooklyn.util.time.Time;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/mysql/DynamicToyMySqlEntityBuilder.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/mysql/DynamicToyMySqlEntityBuilder.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/mysql/DynamicToyMySqlEntityBuilder.java
index 2e304e6..22a8d8d 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/mysql/DynamicToyMySqlEntityBuilder.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/mysql/DynamicToyMySqlEntityBuilder.java
@@ -29,6 +29,7 @@ import org.apache.brooklyn.api.location.OsDetails;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.location.BasicOsDetails.OsVersions;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks;
 import org.apache.brooklyn.entity.stock.BasicStartable;
 import org.slf4j.Logger;
@@ -37,7 +38,6 @@ import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocati
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
 import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.core.task.ssh.SshTasks;
 import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.util.ssh.BashCommands;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbSshDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbSshDriver.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbSshDriver.java
index 226ba20..81b4834 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbSshDriver.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbSshDriver.java
@@ -38,10 +38,10 @@ import org.apache.brooklyn.entity.software.base.AbstractSoftwareProcessSshDriver
 import org.apache.brooklyn.api.location.OsDetails;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.util.net.Urls;
 import org.apache.brooklyn.util.os.Os;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlSshDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlSshDriver.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlSshDriver.java
index c824cc7..95f497d 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlSshDriver.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlSshDriver.java
@@ -41,10 +41,10 @@ import org.apache.brooklyn.api.location.OsDetails;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.BasicOsDetails.OsVersions;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.io.FileUtil;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java
index 205670a..e557090 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java
@@ -25,6 +25,7 @@ import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.Locations;
 import org.apache.brooklyn.effector.core.EffectorBody;
 import org.apache.brooklyn.effector.core.Effectors;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.chef.ChefConfig;
 import org.apache.brooklyn.entity.chef.ChefLifecycleEffectorTasks;
 import org.apache.brooklyn.entity.chef.ChefServerTasks;
@@ -38,7 +39,6 @@ import org.apache.brooklyn.util.collections.Jsonya;
 import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.ssh.BashCommands;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
index 0d19989..cbb289b 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
@@ -40,12 +40,12 @@ import javax.annotation.Nullable;
 
 import org.apache.brooklyn.api.location.OsDetails;
 import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.core.task.ssh.SshTasks;
 import org.apache.brooklyn.util.core.task.ssh.SshTasks.OnFailingTask;
 import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlChefTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlChefTest.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlChefTest.java
index fe45f78..bd9ec6b 100644
--- a/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlChefTest.java
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlChefTest.java
@@ -25,6 +25,7 @@ import org.slf4j.LoggerFactory;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 import org.apache.brooklyn.effector.core.EffectorTasks;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.chef.ChefLiveTestSupport;
 import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
 import org.apache.brooklyn.entity.database.VogellaExampleAccess;
@@ -32,7 +33,6 @@ import org.apache.brooklyn.api.location.PortRange;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.PortRanges;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeSshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeSshDriver.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeSshDriver.java
index ad65cce..832a886 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeSshDriver.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeSshDriver.java
@@ -35,6 +35,7 @@ import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.Machines;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -51,7 +52,6 @@ import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
 import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.util.core.text.TemplateProcessor;
 import org.apache.brooklyn.util.exceptions.Exceptions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
index 6a3a89d..7a8ae35 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
@@ -39,6 +39,7 @@ import org.apache.brooklyn.core.entity.drivers.downloads.BasicDownloadRequiremen
 import org.apache.brooklyn.core.entity.drivers.downloads.DownloadProducerFromUrlAttribute;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.software.base.AbstractSoftwareProcessSshDriver;
 import org.apache.http.auth.UsernamePasswordCredentials;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
@@ -51,7 +52,6 @@ import org.apache.brooklyn.util.core.task.DynamicTasks;
 import org.apache.brooklyn.util.core.task.TaskBuilder;
 import org.apache.brooklyn.util.core.task.TaskTags;
 import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.repeat.Repeater;
 import org.apache.brooklyn.util.ssh.BashCommands;
 import org.apache.brooklyn.util.text.NaturalOrderComparator;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeSshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeSshDriver.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeSshDriver.java
index 802d2da..943a193 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeSshDriver.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeSshDriver.java
@@ -41,12 +41,12 @@ import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.api.location.OsDetails;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.java.JavaSoftwareProcessSshDriver;
 import org.apache.brooklyn.entity.software.base.lifecycle.ScriptHelper;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.core.task.ssh.SshTasks;
 import org.apache.brooklyn.util.net.Urls;
 import org.apache.brooklyn.util.os.Os;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/software/osgi/src/test/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerTest.java
----------------------------------------------------------------------
diff --git a/software/osgi/src/test/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerTest.java b/software/osgi/src/test/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerTest.java
index 2d2058a..ae525cd 100644
--- a/software/osgi/src/test/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerTest.java
+++ b/software/osgi/src/test/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerTest.java
@@ -29,10 +29,10 @@ import org.apache.brooklyn.api.location.NoMachinesAvailableException;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.test.support.TestResourceUnavailableException;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.text.Identifiers;
 import org.testng.Assert;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4820fa46/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedMySqlNodeImpl.java
----------------------------------------------------------------------
diff --git a/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedMySqlNodeImpl.java b/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedMySqlNodeImpl.java
index 65ddf3b..fc0aa4c 100644
--- a/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedMySqlNodeImpl.java
+++ b/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedMySqlNodeImpl.java
@@ -23,6 +23,7 @@ import static java.lang.String.format;
 import java.util.concurrent.Callable;
 
 import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.database.mysql.MySqlNode;
 import org.apache.brooklyn.entity.database.mysql.MySqlNodeImpl;
 import org.apache.brooklyn.entity.database.mysql.MySqlSshDriver;
@@ -32,7 +33,6 @@ import org.apache.brooklyn.sensor.feed.function.FunctionFeed;
 import org.apache.brooklyn.sensor.feed.function.FunctionPollConfig;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
-import org.apache.brooklyn.util.core.task.ssh.SshEffectorTasks;
 import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.util.time.CountdownTimer;
 import org.apache.brooklyn.util.time.Duration;


[09/36] incubator-brooklyn git commit: Rename o.a.b.effector.core to o.a.b.core.effector

Posted by he...@apache.org.
Rename o.a.b.effector.core to o.a.b.core.effector

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

Branch: refs/heads/master
Commit: 8dbb0e4b2de44840f23f6cce2862dc41ae9ff307
Parents: 4820fa4
Author: Aled Sage <al...@gmail.com>
Authored: Wed Aug 19 22:39:55 2015 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Wed Aug 19 22:39:55 2015 +0100

----------------------------------------------------------------------
 .../core/effector/AbstractEffector.java         |  90 ++++
 .../core/effector/AddChildrenEffector.java      | 117 +++++
 .../brooklyn/core/effector/AddEffector.java     | 116 +++++
 .../brooklyn/core/effector/AddSensor.java       | 126 ++++++
 .../core/effector/BasicParameterType.java       | 116 +++++
 .../brooklyn/core/effector/EffectorAndBody.java |  60 +++
 .../brooklyn/core/effector/EffectorBase.java    | 106 +++++
 .../brooklyn/core/effector/EffectorBody.java    | 100 +++++
 .../brooklyn/core/effector/EffectorTasks.java   | 229 ++++++++++
 .../core/effector/EffectorWithBody.java         |  32 ++
 .../brooklyn/core/effector/Effectors.java       | 202 +++++++++
 .../core/effector/ExplicitEffector.java         |  74 ++++
 .../brooklyn/core/effector/MethodEffector.java  | 180 ++++++++
 .../core/effector/ssh/SshEffectorTasks.java     | 335 ++++++++++++++
 .../apache/brooklyn/core/entity/Entities.java   |   2 +-
 .../brooklyn/core/entity/EntityDynamicType.java |  14 +-
 .../core/entity/trait/MemberReplaceable.java    |   2 +-
 .../brooklyn/core/entity/trait/Resizable.java   |   2 +-
 .../brooklyn/core/entity/trait/Startable.java   |   6 +-
 .../core/entity/trait/StartableMethods.java     |   2 +-
 .../core/mgmt/EntityManagementUtils.java        |   2 +-
 .../core/mgmt/internal/EffectorUtils.java       |   2 +-
 .../mgmt/internal/LocalManagementContext.java   |   2 +-
 .../core/mgmt/persist/XmlMementoSerializer.java |   8 +-
 .../core/objs/proxy/EntityProxyImpl.java        |   2 +-
 .../effector/core/AbstractEffector.java         |  90 ----
 .../effector/core/AddChildrenEffector.java      | 117 -----
 .../brooklyn/effector/core/AddEffector.java     | 116 -----
 .../brooklyn/effector/core/AddSensor.java       | 126 ------
 .../effector/core/BasicParameterType.java       | 116 -----
 .../brooklyn/effector/core/EffectorAndBody.java |  60 ---
 .../brooklyn/effector/core/EffectorBase.java    | 106 -----
 .../brooklyn/effector/core/EffectorBody.java    | 100 -----
 .../brooklyn/effector/core/EffectorTasks.java   | 229 ----------
 .../effector/core/EffectorWithBody.java         |  32 --
 .../brooklyn/effector/core/Effectors.java       | 202 ---------
 .../effector/core/ExplicitEffector.java         |  74 ----
 .../brooklyn/effector/core/MethodEffector.java  | 180 --------
 .../effector/core/ssh/SshEffectorTasks.java     | 334 --------------
 .../brooklyn/entity/group/DynamicCluster.java   |   2 +-
 .../entity/group/DynamicClusterImpl.java        |   2 +-
 .../entity/group/DynamicFabricImpl.java         |   2 +-
 .../brooklyn/entity/group/DynamicGroup.java     |   2 +-
 .../entity/group/DynamicRegionsFabric.java      |   2 +-
 .../entity/group/QuarantineGroupImpl.java       |   2 +-
 .../brooklyn/sensor/core/HttpRequestSensor.java |   2 +-
 .../brooklyn/sensor/core/StaticSensor.java      |   2 +-
 .../windows/WindowsPerformanceCounterFeed.java  |   2 +-
 .../brooklyn/util/core/task/ssh/SshTasks.java   |   2 +-
 .../core/effector/EffectorBasicTest.java        | 183 ++++++++
 .../core/effector/EffectorConcatenateTest.java  | 241 ++++++++++
 .../core/effector/EffectorMetadataTest.java     | 166 +++++++
 .../effector/EffectorSayHiGroovyTest.groovy     | 182 ++++++++
 .../core/effector/EffectorSayHiTest.java        | 173 ++++++++
 .../core/effector/EffectorTaskTest.java         | 437 +++++++++++++++++++
 .../core/effector/ssh/SshEffectorTasksTest.java | 265 +++++++++++
 .../brooklyn/core/entity/DynamicEntityTest.java |   2 +-
 .../brooklyn/core/entity/EntityTypeTest.java    |   2 +-
 .../brooklyn/core/entity/hello/HelloEntity.java |   2 +-
 .../mgmt/osgi/OsgiVersionMoreEntityTest.java    |   2 +-
 .../rebind/RebindEntityDynamicTypeInfoTest.java |   4 +-
 .../brooklyn/core/test/entity/TestEntity.java   |   2 +-
 .../effector/core/EffectorBasicTest.java        | 183 --------
 .../effector/core/EffectorConcatenateTest.java  | 241 ----------
 .../effector/core/EffectorMetadataTest.java     | 166 -------
 .../core/EffectorSayHiGroovyTest.groovy         | 179 --------
 .../effector/core/EffectorSayHiTest.java        | 173 --------
 .../effector/core/EffectorTaskTest.java         | 437 -------------------
 .../effector/core/ssh/SshEffectorTasksTest.java | 264 -----------
 .../location/ssh/SshMachineLocationTest.java    |   6 +-
 .../util/core/task/ssh/SshTasksTest.java        |   2 +-
 .../brooklyn/demo/CumulusRDFApplication.java    |   6 +-
 .../brooklyn/policy/loadbalancing/Movable.java  |   2 +-
 .../loadbalancing/MockContainerEntity.java      |   2 +-
 .../postgresql/PostgreSqlNodeSaltImpl.java      |   6 +-
 .../entity/salt/SaltLifecycleEffectorTasks.java |   2 +-
 .../apache/brooklyn/entity/salt/SaltTasks.java  |   5 +-
 .../postgresql/PostgreSqlSaltLiveTest.java      |   4 +-
 .../entity/brooklynnode/BrooklynCluster.java    |   2 +-
 .../brooklynnode/BrooklynEntityMirrorImpl.java  |   2 +-
 .../entity/brooklynnode/BrooklynNode.java       |   2 +-
 .../entity/brooklynnode/BrooklynNodeImpl.java   |   4 +-
 .../brooklynnode/BrooklynNodeSshDriver.java     |   2 +-
 .../brooklynnode/RemoteEffectorBuilder.java     |   4 +-
 .../BrooklynClusterUpgradeEffectorBody.java     |   4 +-
 .../BrooklynNodeUpgradeEffectorBody.java        |   6 +-
 .../effector/SelectMasterEffectorBody.java      |   4 +-
 .../SetHighAvailabilityModeEffectorBody.java    |   4 +-
 ...SetHighAvailabilityPriorityEffectorBody.java |   4 +-
 .../entity/chef/ChefLifecycleEffectorTasks.java |   2 +-
 .../brooklyn/entity/chef/ChefSoloTasks.java     |   2 +-
 .../apache/brooklyn/entity/chef/ChefTasks.java  |   4 +-
 .../entity/chef/KnifeConvergeTaskFactory.java   |   2 +-
 .../java/JavaSoftwareProcessSshDriver.java      |   4 +-
 .../entity/java/JmxAttributeSensor.java         |   2 +-
 .../brooklyn/entity/machine/MachineEntity.java  |   2 +-
 .../entity/machine/MachineEntityImpl.java       |   2 +-
 .../entity/machine/pool/ServerPool.java         |   2 +-
 .../entity/machine/pool/ServerPoolImpl.java     |   2 +-
 .../base/AbstractSoftwareProcessSshDriver.java  |   4 +-
 .../MachineLifecycleEffectorTasks.java          |   6 +-
 .../system_service/InitdServiceInstaller.java   |   2 +-
 .../system_service/SystemServiceEnricher.java   |   2 +-
 .../brooklyn/sensor/ssh/SshCommandEffector.java |  12 +-
 .../brooklyn/sensor/ssh/SshCommandSensor.java   |   2 +-
 .../brooklynnode/SelectMasterEffectorTest.java  |   2 +-
 .../ChefSoloDriverMySqlEntityLiveTest.java      |   2 +-
 .../mysql/ChefSoloDriverToyMySqlEntity.java     |   2 +-
 .../software/base/SoftwareEffectorTest.java     |   6 +-
 .../base/SoftwareProcessEntityTest.java         |   2 +-
 .../base/SoftwareProcessSubclassTest.java       |   4 +-
 .../test/mysql/AbstractToyMySqlEntityTest.java  |   2 +-
 .../mysql/DynamicToyMySqlEntityBuilder.java     |   2 +-
 .../test/ssh/SshCommandIntegrationTest.java     |   2 +-
 .../SystemServiceEnricherTest.java              |   2 +-
 .../entity/database/DatastoreMixins.java        |   2 +-
 .../database/mariadb/MariaDbNodeImpl.java       |   2 +-
 .../database/mariadb/MariaDbSshDriver.java      |   2 +-
 .../entity/database/mysql/MySqlNode.java        |   2 +-
 .../entity/database/mysql/MySqlNodeImpl.java    |   2 +-
 .../entity/database/mysql/MySqlSshDriver.java   |   2 +-
 .../database/postgresql/PostgreSqlNode.java     |   2 +-
 .../PostgreSqlNodeChefImplFromScratch.java      |   6 +-
 .../database/postgresql/PostgreSqlNodeImpl.java |   2 +-
 .../postgresql/PostgreSqlSshDriver.java         |   2 +-
 .../database/postgresql/PostgreSqlChefTest.java |   4 +-
 .../nosql/cassandra/CassandraDatacenter.java    |   4 +-
 .../cassandra/CassandraDatacenterImpl.java      |   2 +-
 .../entity/nosql/cassandra/CassandraFabric.java |   2 +-
 .../nosql/cassandra/CassandraNodeImpl.java      |   2 +-
 .../nosql/cassandra/CassandraNodeSshDriver.java |   2 +-
 .../nosql/couchbase/CouchbaseClusterImpl.java   |   2 +-
 .../entity/nosql/couchbase/CouchbaseNode.java   |   4 +-
 .../nosql/couchbase/CouchbaseNodeImpl.java      |   2 +-
 .../nosql/couchbase/CouchbaseNodeSshDriver.java |   2 +-
 .../entity/nosql/mongodb/MongoDBClient.java     |   2 +-
 .../brooklyn/entity/nosql/riak/RiakNode.java    |   2 +-
 .../entity/nosql/riak/RiakNodeSshDriver.java    |   2 +-
 .../entity/osgi/karaf/KarafContainer.java       |   2 +-
 .../entity/osgi/karaf/KarafContainerTest.java   |   2 +-
 .../brooklyn/entity/proxy/LoadBalancer.java     |   2 +-
 .../entity/proxy/nginx/NginxController.java     |   2 +-
 .../brooklyn/entity/proxy/nginx/UrlMapping.java |   2 +-
 .../entity/webapp/DynamicWebAppClusterImpl.java |   2 +-
 .../entity/webapp/JavaWebAppService.java        |   2 +-
 .../spi/dsl/BrooklynDslDeferredSupplier.java    |   2 +-
 .../camp/brooklyn/EntitiesYamlTest.java         |   2 +-
 .../TestSensorAndEffectorInitializer.java       |   4 +-
 .../brooklyn/VanillaBashNetcatYamlTest.java     |   2 +-
 .../brooklyn/test/lite/CampYamlLiteTest.java    |   4 +-
 .../qa/load/SimulatedMySqlNodeImpl.java         |   2 +-
 .../testing/mocks/RestMockSimpleEntity.java     |   2 +-
 .../test/osgi/entities/more/MoreEntity.java     |   2 +-
 .../test/osgi/entities/more/MoreEntityImpl.java |   2 +-
 .../test/osgi/entities/more/MoreEntity.java     |   2 +-
 .../test/osgi/entities/more/MoreEntityImpl.java |   2 +-
 .../test/osgi/entities/more/MoreEntity.java     |   2 +-
 .../test/osgi/entities/more/MoreEntityImpl.java |   2 +-
 158 files changed, 3694 insertions(+), 3690 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/effector/AbstractEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/AbstractEffector.java b/core/src/main/java/org/apache/brooklyn/core/effector/AbstractEffector.java
new file mode 100644
index 0000000..4acd0e0
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/AbstractEffector.java
@@ -0,0 +1,90 @@
+/*
+ * 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.core.effector;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.effector.ParameterType;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.effector.EffectorTasks.EffectorTaskFactory;
+import org.apache.brooklyn.core.mgmt.internal.EffectorUtils;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.core.task.DynamicSequentialTask;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * The abstract {@link Effector} implementation.
+ * 
+ * The concrete subclass (often anonymous) will supply the {@link #call(Entity, Map)} implementation,
+ * and the fields in the constructor.
+ */
+public abstract class AbstractEffector<T> extends EffectorBase<T> implements EffectorWithBody<T> {
+
+    private static final long serialVersionUID = 1832435915652457843L;
+    
+    @SuppressWarnings("unused")
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractEffector.class);
+
+    public AbstractEffector(String name, Class<T> returnType, List<ParameterType<?>> parameters, String description) {
+        super(name, returnType, parameters, description);
+    }
+
+    public abstract T call(Entity entity, @SuppressWarnings("rawtypes") Map parameters);
+
+    /** Convenience for named-parameter syntax (needs map in first argument) */
+    public T call(Entity entity) { return call(ImmutableMap.of(), entity); }
+
+    /** Convenience for named-parameter syntax (needs map in first argument) */
+    public T call(@SuppressWarnings("rawtypes") Map parameters, Entity entity) { return call(entity, parameters); }
+
+    /** @deprecated since 0.7.0 use {@link #getFlagsForTaskInvocationAt(Entity, Effector, ConfigBag)} */ @Deprecated
+    protected final Map<Object,Object> getFlagsForTaskInvocationAt(Entity entity) {
+        return getFlagsForTaskInvocationAt(entity, this, null);
+    }
+    /** subclasses may override to add additional flags, but they should include the flags returned here 
+     * unless there is very good reason not to */
+    protected Map<Object,Object> getFlagsForTaskInvocationAt(Entity entity, Effector<T> effector, ConfigBag parameters) {
+        return EffectorUtils.getTaskFlagsForEffectorInvocation(entity, effector, parameters);
+    }
+    
+    /** not meant for overriding; subclasses should override the abstract {@link #call(Entity, Map)} method in this class */
+    @Override
+    public final EffectorTaskFactory<T> getBody() {
+        return new EffectorTaskFactory<T>() {
+            @Override
+            public Task<T> newTask(final Entity entity, final Effector<T> effector, final ConfigBag parameters) {
+                return new DynamicSequentialTask<T>(
+                        getFlagsForTaskInvocationAt(entity, AbstractEffector.this, parameters),
+                        new Callable<T>() {
+                            @Override public T call() {
+                                return AbstractEffector.this.call(parameters.getAllConfig(), entity);
+                            }
+                        });
+            }
+        };
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/effector/AddChildrenEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/AddChildrenEffector.java b/core/src/main/java/org/apache/brooklyn/core/effector/AddChildrenEffector.java
new file mode 100644
index 0000000..f2730ca
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/AddChildrenEffector.java
@@ -0,0 +1,117 @@
+/*
+ * 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.core.effector;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.Effectors.EffectorBuilder;
+import org.apache.brooklyn.core.mgmt.EntityManagementUtils;
+import org.apache.brooklyn.core.mgmt.EntityManagementUtils.CreationResult;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.Beta;
+import com.google.gson.Gson;
+
+/** Entity initializer which defines an effector which adds a child blueprint to an entity.
+ * <p>
+ * One of the config keys {@link #BLUEPRINT_YAML} (containing a YAML blueprint (map or string)) 
+ * or {@link #BLUEPRINT_TYPE} (containing a string referring to a catalog type) should be supplied, but not both.
+ * Parameters defined here are supplied as config during the entity creation.
+ * 
+ * @since 0.7.0 */
+@Beta
+public class AddChildrenEffector extends AddEffector {
+    
+    private static final Logger log = LoggerFactory.getLogger(AddChildrenEffector.class);
+    
+    public static final ConfigKey<Object> BLUEPRINT_YAML = ConfigKeys.newConfigKey(Object.class, "blueprint_yaml");
+    public static final ConfigKey<String> BLUEPRINT_TYPE = ConfigKeys.newStringConfigKey("blueprint_type");
+    public static final ConfigKey<Boolean> AUTO_START = ConfigKeys.newBooleanConfigKey("auto_start");
+    
+    public AddChildrenEffector(ConfigBag params) {
+        super(newEffectorBuilder(params).build());
+    }
+    
+    public AddChildrenEffector(Map<String,String> params) {
+        this(ConfigBag.newInstance(params));
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public static EffectorBuilder<List<String>> newEffectorBuilder(ConfigBag params) {
+        EffectorBuilder<List<String>> eff = (EffectorBuilder) AddEffector.newEffectorBuilder(List.class, params);
+        eff.impl(new Body(eff.buildAbstract(), params));
+        return eff;
+    }
+
+    protected static class Body extends EffectorBody<List<String>> {
+
+        private final Effector<?> effector;
+        private final String blueprintBase;
+        private final Boolean autostart;
+
+        public Body(Effector<?> eff, ConfigBag params) {
+            this.effector = eff;
+            String newBlueprint = null;
+            Object yaml = params.get(BLUEPRINT_YAML);
+            if (yaml instanceof Map) {
+                newBlueprint = new Gson().toJson(yaml);
+            } else if (yaml instanceof String) {
+                newBlueprint = (String) yaml;
+            } else if (yaml!=null) {
+                throw new IllegalArgumentException(this+" requires map or string in "+BLUEPRINT_YAML+"; not "+yaml.getClass()+" ("+yaml+")");
+            }
+            String blueprintType = params.get(BLUEPRINT_TYPE);
+            if (blueprintType!=null) {
+                if (newBlueprint!=null) {
+                    throw new IllegalArgumentException(this+" cannot take both "+BLUEPRINT_TYPE+" and "+BLUEPRINT_YAML);
+                }
+                newBlueprint = "services: [ { type: "+blueprintType+" } ]";
+            }
+            if (newBlueprint==null) {
+                throw new IllegalArgumentException(this+" requires either "+BLUEPRINT_TYPE+" or "+BLUEPRINT_YAML);
+            }
+            blueprintBase = newBlueprint;
+            autostart = params.get(AUTO_START);
+        }
+
+        @Override
+        public List<String> call(ConfigBag params) {
+            params = getMergedParams(effector, params);
+            
+            String blueprint = blueprintBase;
+            if (!params.isEmpty()) { 
+                blueprint = blueprint+"\n"+"brooklyn.config: "+
+                    new Gson().toJson(params.getAllConfig());
+            }
+
+            log.debug(this+" adding children to "+entity()+":\n"+blueprint);
+            CreationResult<List<Entity>, List<String>> result = EntityManagementUtils.addChildren(entity(), blueprint, autostart);
+            log.debug(this+" added children to "+entity()+": "+result.get());
+            return result.task().getUnchecked();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/effector/AddEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/AddEffector.java b/core/src/main/java/org/apache/brooklyn/core/effector/AddEffector.java
new file mode 100644
index 0000000..9590bcf
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/AddEffector.java
@@ -0,0 +1,116 @@
+/*
+ * 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.core.effector;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.effector.ParameterType;
+import org.apache.brooklyn.api.entity.EntityInitializer;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.config.MapConfigKey;
+import org.apache.brooklyn.core.effector.Effectors.EffectorBuilder;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.text.Strings;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+
+/** 
+ * Entity initializer which adds an effector to an entity.
+ * <p>
+ * This instance provides a {@link #newEffectorBuilder(Class, ConfigBag)} 
+ * which returns an abstract (body-less) effector defining:
+ * <li> the name from {@link #EFFECTOR_NAME};
+ * <li> the description from {@link #EFFECTOR_DESCRIPTION}
+ * <li> the parameters from {@link #EFFECTOR_PARAMETER_DEFS}
+ * <p>
+ * Callers should pass the effector to instantiate into the constructor.
+ * Often subclasses will supply a constructor which takes a ConfigBag of parameters,
+ * and a custom {@link #newEffectorBuilder(Class, ConfigBag)} which adds the body
+ * before passing to this class.
+ * <p>
+ * Note that the parameters passed to the call method in the body of the effector implementation
+ * are only those supplied by a user at runtime; in order to merge with default
+ * values, use {@link #getMergedParams(Effector, ConfigBag)}.
+ *  
+ * @since 0.7.0 */
+@Beta
+public class AddEffector implements EntityInitializer {
+    
+    public static final ConfigKey<String> EFFECTOR_NAME = ConfigKeys.newStringConfigKey("name");
+    public static final ConfigKey<String> EFFECTOR_DESCRIPTION = ConfigKeys.newStringConfigKey("description");
+    
+    public static final ConfigKey<Map<String,Object>> EFFECTOR_PARAMETER_DEFS = new MapConfigKey<Object>(Object.class, "parameters");
+
+    final Effector<?> effector;
+    
+    public AddEffector(Effector<?> effector) {
+        this.effector = Preconditions.checkNotNull(effector, "effector");
+    }
+    
+    @Override
+    public void apply(EntityLocal entity) {
+        ((EntityInternal)entity).getMutableEntityType().addEffector(effector);
+    }
+    
+    public static <T> EffectorBuilder<T> newEffectorBuilder(Class<T> type, ConfigBag params) {
+        String name = Preconditions.checkNotNull(params.get(EFFECTOR_NAME), "name must be supplied when defining an effector: %s", params);
+        EffectorBuilder<T> eff = Effectors.effector(type, name);
+        eff.description(params.get(EFFECTOR_DESCRIPTION));
+        
+        Map<String, Object> paramDefs = params.get(EFFECTOR_PARAMETER_DEFS);
+        if (paramDefs!=null) {
+            for (Map.Entry<String, Object> paramDef: paramDefs.entrySet()){
+                if (paramDef!=null) {
+                    String paramName = paramDef.getKey();
+                    Object value = paramDef.getValue();
+                    if (value==null) value = Collections.emptyMap();
+                    if (!(value instanceof Map)) {
+                        if (value instanceof CharSequence && Strings.isBlank((CharSequence) value)) 
+                            value = Collections.emptyMap();
+                    }
+                    if (!(value instanceof Map))
+                        throw new IllegalArgumentException("Illegal argument of type "+value.getClass()+" value '"+value+"' supplied as parameter definition "
+                            + "'"+paramName);
+                    eff.parameter(ConfigKeys.DynamicKeys.newNamedInstance(paramName, (Map<?, ?>) value));
+                }
+            }
+        }
+        
+        return eff;
+    }
+
+    /** returns a ConfigBag containing the merger of the supplied parameters with default values on the effector-defined parameters */
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public static ConfigBag getMergedParams(Effector<?> eff, ConfigBag params) {
+        ConfigBag result = ConfigBag.newInstanceCopying(params);
+        for (ParameterType<?> param: eff.getParameters()) {
+            ConfigKey key = Effectors.asConfigKey(param);
+            if (!result.containsKey(key))
+                result.configure(key, params.get(key));
+        }
+        return result;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java b/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java
new file mode 100644
index 0000000..3c08831
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java
@@ -0,0 +1,126 @@
+/*
+ * 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.core.effector;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.EntityInitializer;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.javalang.Boxing;
+import org.apache.brooklyn.util.time.Duration;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+
+/**
+ * Creates a new {@link AttributeSensor} on an entity.
+ * <p>
+ * The configuration can include the sensor {@code name}, {@code period} and {@code targetType}.
+ * For the targetType, currently this only supports classes on the initial classpath, not those in
+ * OSGi bundles added at runtime.
+ *
+ * @since 0.7.0
+ */
+@Beta
+public class AddSensor<T> implements EntityInitializer {
+
+    public static final ConfigKey<String> SENSOR_NAME = ConfigKeys.newStringConfigKey("name", "The name of the sensor to create");
+    public static final ConfigKey<Duration> SENSOR_PERIOD = ConfigKeys.newConfigKey(Duration.class, "period", "Period, including units e.g. 1m or 5s or 200ms; default 5 minutes", Duration.FIVE_MINUTES);
+    public static final ConfigKey<String> SENSOR_TYPE = ConfigKeys.newStringConfigKey("targetType", "Target type for the value; default String", "java.lang.String");
+
+    protected final String name;
+    protected final Duration period;
+    protected final String type;
+    protected final AttributeSensor<T> sensor;
+
+    public AddSensor(Map<String, String> params) {
+        this(ConfigBag.newInstance(params));
+    }
+
+    public AddSensor(final ConfigBag params) {
+        this.name = Preconditions.checkNotNull(params.get(SENSOR_NAME), "Name must be supplied when defining a sensor");
+        this.period = params.get(SENSOR_PERIOD);
+        this.type = params.get(SENSOR_TYPE);
+        this.sensor = newSensor();
+    }
+
+    @Override
+    public void apply(EntityLocal entity) {
+        ((EntityInternal) entity).getMutableEntityType().addSensor(sensor);
+    }
+
+    private AttributeSensor<T> newSensor() {
+        String className = getFullClassName(type);
+        Class<T> clazz = getType(className);
+        return Sensors.newSensor(clazz, name);
+    }
+
+    @SuppressWarnings("unchecked")
+    protected Class<T> getType(String className) {
+        try {
+            // TODO use OSGi loader (low priority however); also ensure that allows primitives
+            Maybe<Class<?>> primitive = Boxing.getPrimitiveType(className);
+            if (primitive.isPresent()) return (Class<T>) primitive.get();
+            return (Class<T>) Class.forName(className);
+        } catch (ClassNotFoundException e) {
+            if (!className.contains(".")) {
+                // could be assuming "java.lang" package; try again with that
+                try {
+                    return (Class<T>) Class.forName("java.lang."+className);
+                } catch (ClassNotFoundException e2) {
+                    throw new IllegalArgumentException("Invalid target type for sensor "+name+": " + className+" (also tried java.lang."+className+")");
+                }
+            } else {
+                throw new IllegalArgumentException("Invalid target type for sensor "+name+": " + className);
+            }
+        }
+    }
+
+    protected String getFullClassName(String className) {
+        if (className.equalsIgnoreCase("string")) {
+            return "java.lang.String";
+        } else if (className.equalsIgnoreCase("int") || className.equalsIgnoreCase("integer")) {
+            return "java.lang.Integer";
+        } else if (className.equalsIgnoreCase("long")) {
+            return "java.lang.Long";
+        } else if (className.equalsIgnoreCase("float")) {
+            return "java.lang.Float";
+        } else if (className.equalsIgnoreCase("double")) {
+            return "java.lang.Double";
+        } else if (className.equalsIgnoreCase("bool") || className.equalsIgnoreCase("boolean")) {
+            return "java.lang.Boolean";
+        } else if (className.equalsIgnoreCase("byte")) {
+            return "java.lang.Byte";
+        } else if (className.equalsIgnoreCase("char") || className.equalsIgnoreCase("character")) {
+            return "java.lang.Character";
+        } else if (className.equalsIgnoreCase("object")) {
+            return "java.lang.Object";
+        } else {
+            return className;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/effector/BasicParameterType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/BasicParameterType.java b/core/src/main/java/org/apache/brooklyn/core/effector/BasicParameterType.java
new file mode 100644
index 0000000..eb0417f
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/BasicParameterType.java
@@ -0,0 +1,116 @@
+/*
+ * 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.core.effector;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.apache.brooklyn.api.effector.ParameterType;
+
+import com.google.common.base.Objects;
+
+public class BasicParameterType<T> implements ParameterType<T> {
+    private static final long serialVersionUID = -5521879180483663919L;
+    
+    private String name;
+    private Class<T> type;
+    private String description;
+    private Boolean hasDefaultValue = null;
+    private T defaultValue = null;
+
+    public BasicParameterType() {
+        this(Collections.emptyMap());
+    }
+    
+    @SuppressWarnings("unchecked")
+    public BasicParameterType(Map<?, ?> arguments) {
+        if (arguments.containsKey("name")) name = (String) arguments.get("name");
+        if (arguments.containsKey("type")) type = (Class<T>) arguments.get("type");
+        if (arguments.containsKey("description")) description = (String) arguments.get("description");
+        if (arguments.containsKey("defaultValue")) defaultValue = (T) arguments.get("defaultValue");
+    }
+
+    public BasicParameterType(String name, Class<T> type) {
+        this(name, type, null, null, false);
+    }
+    
+    public BasicParameterType(String name, Class<T> type, String description) {
+        this(name, type, description, null, false);
+    }
+    
+    public BasicParameterType(String name, Class<T> type, String description, T defaultValue) {
+        this(name, type, description, defaultValue, true);
+    }
+    
+    public BasicParameterType(String name, Class<T> type, String description, T defaultValue, boolean hasDefaultValue) {
+        this.name = name;
+        this.type = type;
+        this.description = description;
+        this.defaultValue = defaultValue;
+        if (defaultValue!=null && !defaultValue.getClass().equals(Object.class)) {
+            // if default value is null (or is an Object, which is ambiguous on resolution to to rebind), 
+            // don't bother to set this as it creates noise in the persistence files
+            this.hasDefaultValue = hasDefaultValue;
+        }
+    }
+
+    @Override
+    public String getName() { return name; }
+
+    @Override
+    public Class<T> getParameterClass() { return type; }
+    
+    @Override
+    public String getParameterClassName() { return type.getCanonicalName(); }
+
+    @Override
+    public String getDescription() { return description; }
+
+    @Override
+    public T getDefaultValue() {
+        return hasDefaultValue() ? defaultValue : null;
+    }
+
+    public boolean hasDefaultValue() {
+        // a new Object() was previously used to indicate no default value, but that doesn't work well across serialization boundaries!
+        return hasDefaultValue!=null ? hasDefaultValue : defaultValue!=null && !defaultValue.getClass().equals(Object.class);
+    }
+    
+    @Override
+    public String toString() {
+        return Objects.toStringHelper(this).omitNullValues()
+                .add("name", name).add("description", description).add("type", getParameterClassName())
+                .add("defaultValue", defaultValue)
+                .toString();
+    }
+    
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(name, description, type, defaultValue);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        return (obj instanceof ParameterType) &&
+                Objects.equal(name, ((ParameterType<?>)obj).getName()) &&
+                Objects.equal(description, ((ParameterType<?>)obj).getDescription()) &&
+                Objects.equal(type, ((ParameterType<?>)obj).getParameterClass()) &&
+                Objects.equal(defaultValue, ((ParameterType<?>)obj).getDefaultValue());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/effector/EffectorAndBody.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/EffectorAndBody.java b/core/src/main/java/org/apache/brooklyn/core/effector/EffectorAndBody.java
new file mode 100644
index 0000000..49e85b8
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/EffectorAndBody.java
@@ -0,0 +1,60 @@
+/*
+ * 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.core.effector;
+
+import java.util.List;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.effector.ParameterType;
+import org.apache.brooklyn.core.effector.EffectorTasks.EffectorTaskFactory;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+
+@Beta // added in 0.6.0
+public class EffectorAndBody<T> extends EffectorBase<T> implements EffectorWithBody<T> {
+
+    private static final long serialVersionUID = -6023389678748222968L;
+    private final EffectorTaskFactory<T> body;
+
+    public EffectorAndBody(Effector<T> original, EffectorTaskFactory<T> body) {
+        this(original.getName(), original.getReturnType(), original.getParameters(), original.getDescription(), body);
+    }
+    
+    public EffectorAndBody(String name, Class<T> returnType, List<ParameterType<?>> parameters, String description, EffectorTaskFactory<T> body) {
+        super(name, returnType, parameters, description);
+        this.body = body;
+    }
+
+    @Override
+    public EffectorTaskFactory<T> getBody() {
+        return body;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(super.hashCode(), getBody());
+    }
+    
+    @Override
+    public boolean equals(Object other) {
+        return super.equals(other) && Objects.equal(getBody(), ((EffectorAndBody<?>)other).getBody());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/effector/EffectorBase.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/EffectorBase.java b/core/src/main/java/org/apache/brooklyn/core/effector/EffectorBase.java
new file mode 100644
index 0000000..68132c4
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/EffectorBase.java
@@ -0,0 +1,106 @@
+/*
+ * 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.core.effector;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.effector.ParameterType;
+import org.apache.brooklyn.core.effector.EffectorTasks.EffectorTaskFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Objects;
+
+/** concrete implementation of Effector interface, 
+ * but not (at this level of the hirarchy) defining an implementation 
+ * (see {@link EffectorTaskFactory} and {@link EffectorWithBody}) */
+public class EffectorBase<T> implements Effector<T> {
+
+    @SuppressWarnings("unused")
+    private static final Logger log = LoggerFactory.getLogger(EffectorBase.class);
+    
+    private static final long serialVersionUID = -4153962199078384835L;
+    
+    private final String name;
+    private final Class<T> returnType;
+    private final List<ParameterType<?>> parameters;
+    private final String description;
+
+    public EffectorBase(String name, Class<T> returnType, List<ParameterType<?>> parameters, String description) {
+        this.name = name;
+        this.returnType = returnType;
+        this.parameters = new ArrayList<ParameterType<?>>(parameters);
+        this.description = description;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public Class<T> getReturnType() {
+        return returnType;
+    }
+
+    @Override
+    public String getReturnTypeName() {
+        return returnType.getCanonicalName();
+    }
+
+    @Override
+    public List<ParameterType<?>> getParameters() {
+        return parameters;
+    }
+
+    @Override
+    public String getDescription() {
+        return description;
+    }
+
+    @Override
+    public String toString() {
+        List<String> parameterNames = new ArrayList<String>(parameters.size());
+        for (ParameterType<?> parameter: parameters) {
+            String parameterName = (parameter.getName() != null) ? parameter.getName() : "<unknown>";
+            parameterNames.add(parameterName);
+        }
+        return name+"["+Joiner.on(",").join(parameterNames)+"]";
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(name, returnType, parameters, description);
+    }
+    
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof EffectorBase)) return false;
+        if (!(other.getClass().equals(getClass()))) return false;
+        if (!Objects.equal(hashCode(), other.hashCode())) return false;
+        return Objects.equal(getName(), ((EffectorBase<?>)other).getName()) &&
+            Objects.equal(getReturnType(), ((EffectorBase<?>)other).getReturnType()) &&
+            Objects.equal(getParameters(), ((EffectorBase<?>)other).getParameters()) &&
+            Objects.equal(getDescription(), ((EffectorBase<?>)other).getDescription());
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/effector/EffectorBody.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/EffectorBody.java b/core/src/main/java/org/apache/brooklyn/core/effector/EffectorBody.java
new file mode 100644
index 0000000..b1643ba
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/EffectorBody.java
@@ -0,0 +1,100 @@
+/*
+ * 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.core.effector;
+
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.api.mgmt.TaskAdaptable;
+import org.apache.brooklyn.api.mgmt.TaskFactory;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.core.flags.TypeCoercions;
+import org.apache.brooklyn.util.core.task.DynamicSequentialTask;
+import org.apache.brooklyn.util.core.task.DynamicTasks;
+import org.apache.brooklyn.util.core.task.Tasks;
+
+import com.google.common.annotations.Beta;
+
+/** Typical implementations override {@link #main(ConfigBag)} to do the work of the effector
+ * <p>
+ * See also {@link EffectorTasks}: possibly this will be deleted in preference for an approach based on {@link EffectorTasks}. 
+ * 
+ * @since 0.6.0
+ **/
+@Beta
+public abstract class EffectorBody<T> {
+    /** Does the work of the effector, either in place, or (better) by building up
+     * subtasks, which can by added using {@link DynamicTasks} methods
+     * (and various convenience methods which do that automatically; see subclasses of EffectorBody 
+     * for more info on usage; or see {@link DynamicSequentialTask} for details of the threading model
+     * by which added tasks are placed in a secondary thread)
+     * <p>
+     * The associated entity can be accessed through the {@link #entity()} method.
+     */
+    public abstract T call(ConfigBag parameters);
+    
+    // NB: we could also support an 'init' method which is done at creation,
+    // as a place where implementers can describe the structure of the task before it executes
+    // (and init gets invoked in EffectorBodyTaskFactory.newTask _before_ the task is submitted and main is called)
+    
+    
+    // ---- convenience method(s) for implementers of main -- see subclasses and *Tasks statics for more
+    
+    protected EntityInternal entity() {
+        return (EntityInternal) BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
+    }
+    
+    protected <V extends TaskAdaptable<?>> V queue(V task) {
+        return DynamicTasks.queue(task);
+    }
+
+    protected <V extends TaskAdaptable<?>> void queue(V task1, V task2, V ...tasks) {
+        DynamicTasks.queue(task1);
+        DynamicTasks.queue(task2);
+        for (V task: tasks)
+            DynamicTasks.queue(task);
+    }
+
+    protected <V extends TaskFactory<?>> void queue(V task1, V task2, V ...tasks) {
+        DynamicTasks.queue(task1.newTask());
+        DynamicTasks.queue(task2.newTask());
+        for (V task: tasks)
+            DynamicTasks.queue(task.newTask());
+    }
+    
+    protected <U extends TaskAdaptable<?>> U queue(TaskFactory<U> task) {
+        return DynamicTasks.queue(task.newTask());
+    }
+    
+    /** see {@link DynamicTasks#waitForLast()} */
+    protected Task<?> waitForLast() {
+        return DynamicTasks.waitForLast();
+    }
+
+    /** Returns the result of the last task queued in this context, coerced to the given type */
+    protected <V> V last(Class<V> type) {
+        Task<?> last = waitForLast();
+        if (last==null)
+            throw new IllegalStateException("No last task available (in "+DynamicTasks.getTaskQueuingContext()+")");
+        if (!Tasks.isQueuedOrSubmitted(last))
+            throw new IllegalStateException("Last task "+last+" has not been queued or submitted; will not block on its result");
+        
+        return TypeCoercions.coerce(last.getUnchecked(), type);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/effector/EffectorTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/EffectorTasks.java b/core/src/main/java/org/apache/brooklyn/core/effector/EffectorTasks.java
new file mode 100644
index 0000000..39eb79b
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/EffectorTasks.java
@@ -0,0 +1,229 @@
+/*
+ * 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.core.effector;
+
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.effector.ParameterType;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.api.mgmt.TaskAdaptable;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.location.Machines;
+import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.core.mgmt.internal.EffectorUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.core.task.DynamicSequentialTask;
+import org.apache.brooklyn.util.core.task.DynamicTasks;
+import org.apache.brooklyn.util.core.task.TaskBuilder;
+import org.apache.brooklyn.util.core.task.Tasks;
+import org.apache.brooklyn.util.javalang.Reflections;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+
+/**
+ * Miscellaneous tasks which are useful in effectors.
+ * @since 0.6.0
+ */
+@Beta
+public class EffectorTasks {
+
+    @SuppressWarnings("unused")
+    private static final Logger log = LoggerFactory.getLogger(EffectorTasks.class);
+    
+    public interface EffectorTaskFactory<T> {
+        public abstract TaskAdaptable<T> newTask(Entity entity, Effector<T> effector, ConfigBag parameters);
+    }
+    
+    /** wrapper for {@link EffectorBody} which simply runs that body on each invocation;
+     * the body must be thread safe and ideally stateless */
+    public static class EffectorBodyTaskFactory<T> implements EffectorTaskFactory<T> {
+        private final EffectorBody<T> effectorBody;
+        public EffectorBodyTaskFactory(EffectorBody<T> effectorBody) {
+            this.effectorBody = effectorBody;
+        }
+        
+        @Override
+        public Task<T> newTask(final Entity entity, final org.apache.brooklyn.api.effector.Effector<T> effector, final ConfigBag parameters) {
+            final AtomicReference<DynamicSequentialTask<T>> dst = new AtomicReference<DynamicSequentialTask<T>>();
+
+            dst.set(new DynamicSequentialTask<T>(
+                    getFlagsForTaskInvocationAt(entity, effector, parameters), 
+                    new Callable<T>() {
+                        @Override
+                        public T call() throws Exception {
+                            try {
+                                DynamicTasks.setTaskQueueingContext(dst.get());
+                                return effectorBody.call(parameters);
+                            } finally {
+                                DynamicTasks.removeTaskQueueingContext();
+                            }
+                        }
+                    }) {
+                        @Override
+                        public void handleException(Throwable throwable) throws Exception {
+                            EffectorUtils.handleEffectorException(entity, effector, throwable);
+                        }
+                    });
+            return dst.get();
+        };
+
+        /** @deprecated since 0.7.0 use {@link #getFlagsForTaskInvocationAt(Entity, Effector, ConfigBag)} */ @Deprecated
+        protected final Map<Object,Object> getFlagsForTaskInvocationAt(Entity entity, Effector<?> effector) {
+            return getFlagsForTaskInvocationAt(entity, effector, null);
+        }
+        /** subclasses may override to add additional flags, but they should include the flags returned here 
+         * unless there is very good reason not to; default impl returns a MutableMap */
+        protected Map<Object,Object> getFlagsForTaskInvocationAt(Entity entity, Effector<?> effector, ConfigBag parameters) {
+            return EffectorUtils.getTaskFlagsForEffectorInvocation(entity, effector, parameters);
+        }
+    }
+    
+    /** wrapper for {@link EffectorTaskFactory} which ensures effector task tags are applied to it if needed
+     * (wrapping in a task if needed); without this, {@link EffectorBody}-based effectors get it by
+     * virtue of the call to {@link #getFlagsForTaskInvocationAt(Entity,Effector,ConfigBag)} therein
+     * but {@link EffectorTaskFactory}-based effectors generate a task without the right tags
+     * to be able to tell using {@link BrooklynTaskTags} the effector-context of the task 
+     * <p>
+     * this gets applied automatically so marked as package-private */
+    static class EffectorMarkingTaskFactory<T> implements EffectorTaskFactory<T> {
+        private final EffectorTaskFactory<T> effectorTaskFactory;
+        public EffectorMarkingTaskFactory(EffectorTaskFactory<T> effectorTaskFactory) {
+            this.effectorTaskFactory = effectorTaskFactory;
+        }
+        
+        @Override
+        public Task<T> newTask(final Entity entity, final org.apache.brooklyn.api.effector.Effector<T> effector, final ConfigBag parameters) {
+            if (effectorTaskFactory instanceof EffectorBodyTaskFactory)
+                return effectorTaskFactory.newTask(entity, effector, parameters).asTask();
+            // if we're in an effector context for this effector already, then also pass through
+            if (BrooklynTaskTags.isInEffectorTask(Tasks.current(), entity, effector, false))
+                return effectorTaskFactory.newTask(entity, effector, parameters).asTask();
+            // otherwise, create the task inside an appropriate effector body so tags, name, etc are set correctly
+            return new EffectorBodyTaskFactory<T>(new EffectorBody<T>() {
+                @Override
+                public T call(ConfigBag parameters) {
+                    TaskAdaptable<T> t = DynamicTasks.queue(effectorTaskFactory.newTask(entity, effector, parameters));
+                    return t.asTask().getUnchecked();
+                }
+            }).newTask(entity, effector, parameters);
+        }
+    }
+    
+    public static <T> ConfigKey<T> asConfigKey(ParameterType<T> t) {
+        return ConfigKeys.newConfigKey(t.getParameterClass(), t.getName());
+    }
+    
+    public static <T> ParameterTask<T> parameter(ParameterType<T> t) {
+        return new ParameterTask<T>(asConfigKey(t)).
+                name("parameter "+t);
+    }
+    public static <T> ParameterTask<T> parameter(Class<T> type, String name) {
+        return new ParameterTask<T>(ConfigKeys.newConfigKey(type, name)).
+                name("parameter "+name+" ("+type+")");
+    }
+    public static <T> ParameterTask<T> parameter(final ConfigKey<T> p) {
+        return new ParameterTask<T>(p);
+    }
+    public static class ParameterTask<T> implements EffectorTaskFactory<T> {
+        final ConfigKey<T> p;
+        private TaskBuilder<T> builder;
+        public ParameterTask(ConfigKey<T> p) {
+            this.p = p;
+            this.builder = Tasks.<T>builder().name("parameter "+p);
+        }
+        public ParameterTask<T> name(String taskName) {
+            builder.name(taskName);
+            return this;
+        }
+        @Override
+        public Task<T> newTask(Entity entity, Effector<T> effector, final ConfigBag parameters) {
+            return builder.body(new Callable<T>() {
+                @Override
+                public T call() throws Exception {
+                    return parameters.get(p);
+                }
+                
+            }).build();
+        }
+        
+    }
+
+    public static <T> EffectorTaskFactory<T> of(final Task<T> task) {
+        return new EffectorTaskFactory<T>() {
+            @Override
+            public Task<T> newTask(Entity entity, Effector<T> effector, ConfigBag parameters) {
+                return task;
+            }
+        };
+    }
+
+    /** Finds the entity where this task is running
+     * @throws NullPointerException if there is none (no task, or no context entity for that task) */
+    public static Entity findEntity() {
+        return Preconditions.checkNotNull(BrooklynTaskTags.getTargetOrContextEntity(Tasks.current()),
+                "This must be executed in a task whose execution context has a target or context entity " +
+                "(i.e. it must be run from within an effector)");
+    }
+
+    /** Finds the entity where this task is running, casted to the given Entity subtype
+     * @throws NullPointerException if there is none
+     * @throws IllegalArgumentException if it is not of the indicated type */
+    public static <T extends Entity> T findEntity(Class<T> type) {
+        Entity t = findEntity();
+        return Reflections.cast(t, type);
+    }
+
+    /** Finds a unique {@link SshMachineLocation} attached to the entity 
+     * where this task is running
+     * @throws NullPointerException if {@link #findEntity()} fails
+     * @throws IllegalStateException if call to {@link #getSshMachine(Entity)} fails */
+    public static SshMachineLocation findSshMachine() {
+        return getSshMachine(findEntity());
+    }
+
+    /** Finds a unique {@link SshMachineLocation} attached to the supplied entity 
+     * @throws IllegalStateException if there is not a unique such {@link SshMachineLocation} */
+    public static SshMachineLocation getSshMachine(Entity entity) {
+        try {
+            return Machines.findUniqueSshMachineLocation(entity.getLocations()).get();
+        } catch (Exception e) {
+            throw new IllegalStateException("Entity "+entity+" (in "+Tasks.current()+") requires a single SshMachineLocation, but has "+entity.getLocations(), e);
+        }
+    }
+
+    /** Finds a unique {@link WinRmMachineLocation} attached to the supplied entity
+     * @throws IllegalStateException if there is not a unique such {@link WinRmMachineLocation} */
+    public static WinRmMachineLocation getWinRmMachine(Entity entity) {
+        try {
+            return Machines.findUniqueWinRmMachineLocation(entity.getLocations()).get();
+        } catch (Exception e) {
+            throw new IllegalStateException("Entity "+entity+" (in "+Tasks.current()+") requires a single WinRmMachineLocation, but has "+entity.getLocations(), e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/effector/EffectorWithBody.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/EffectorWithBody.java b/core/src/main/java/org/apache/brooklyn/core/effector/EffectorWithBody.java
new file mode 100644
index 0000000..67dba14
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/EffectorWithBody.java
@@ -0,0 +1,32 @@
+/*
+ * 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.core.effector;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.core.effector.EffectorTasks.EffectorTaskFactory;
+
+import com.google.common.annotations.Beta;
+
+@Beta // added in 0.6.0
+public interface EffectorWithBody<T> extends Effector<T> {
+
+    /** returns the body of the effector, i.e. a factory which can generate tasks which can run */
+    public EffectorTaskFactory<T> getBody();
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java b/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java
new file mode 100644
index 0000000..63ea52d
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java
@@ -0,0 +1,202 @@
+/*
+ * 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.core.effector;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.effector.ParameterType;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.mgmt.TaskAdaptable;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.EffectorTasks.EffectorBodyTaskFactory;
+import org.apache.brooklyn.core.effector.EffectorTasks.EffectorMarkingTaskFactory;
+import org.apache.brooklyn.core.effector.EffectorTasks.EffectorTaskFactory;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.core.task.Tasks;
+import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class Effectors {
+
+    private static final Logger log = LoggerFactory.getLogger(Effectors.class);
+    
+    public static class EffectorBuilder<T> {
+        private Class<T> returnType;
+        private String effectorName;
+        private String description;
+        private Map<String,ParameterType<?>> parameters = new LinkedHashMap<String,ParameterType<?>>();
+        private EffectorTaskFactory<T> impl;
+        
+        private EffectorBuilder(Class<T> returnType, String effectorName) {
+            this.returnType = returnType;
+            this.effectorName = effectorName;
+        }
+        public EffectorBuilder<T> description(String description) {
+            this.description = description;
+            return this;                
+        }
+        public EffectorBuilder<T> parameter(Class<?> paramType, String paramName) {
+            return parameter(paramType, paramName, null, null);
+        }
+        public EffectorBuilder<T> parameter(Class<?> paramType, String paramName, String paramDescription) {
+            return parameter(paramType, paramName, paramDescription, null);                
+        }
+        public <V> EffectorBuilder<T> parameter(Class<V> paramType, String paramName, String paramDescription, V defaultValue) {
+            return parameter(new BasicParameterType<V>(paramName, paramType, paramDescription, defaultValue));
+        }
+        public <V> EffectorBuilder<T> parameter(ConfigKey<V> key) {
+            return parameter(asParameterType(key));
+        }
+        public EffectorBuilder<T> parameter(ParameterType<?> p) {
+            // allow redeclaring, e.g. for the case where we are overriding an existing effector
+            parameters.put(p.getName(), p);
+            return this;
+        }
+        public EffectorBuilder<T> impl(EffectorTaskFactory<T> taskFactory) {
+            this.impl = new EffectorMarkingTaskFactory<T>(taskFactory);
+            return this;
+        }
+        public EffectorBuilder<T> impl(EffectorBody<T> effectorBody) {
+            this.impl = new EffectorBodyTaskFactory<T>(effectorBody);
+            return this;
+        }
+        /** returns the effector, with an implementation (required); @see {@link #buildAbstract()} */
+        public Effector<T> build() {
+             Preconditions.checkNotNull(impl, "Cannot create effector %s with no impl (did you forget impl? or did you mean to buildAbstract?)", effectorName);
+             return new EffectorAndBody<T>(effectorName, returnType, ImmutableList.copyOf(parameters.values()), description, impl);
+        }
+        
+        /** returns an abstract effector, where the body will be defined later/elsewhere 
+         * (impl must not be set) */
+        public Effector<T> buildAbstract() {
+            Preconditions.checkArgument(impl==null, "Cannot create abstract effector {} as an impl is defined", effectorName);
+            return new EffectorBase<T>(effectorName, returnType, ImmutableList.copyOf(parameters.values()), description);
+        }
+    }
+
+    /** creates a new effector builder with the given name and return type */
+    public static <T> EffectorBuilder<T> effector(Class<T> returnType, String effectorName) {
+        return new EffectorBuilder<T>(returnType, effectorName);
+    }
+
+    /** creates a new effector builder to _override_ the given effector */
+    public static <T> EffectorBuilder<T> effector(Effector<T> base) {
+        EffectorBuilder<T> builder = new EffectorBuilder<T>(base.getReturnType(), base.getName());
+        for (ParameterType<?> p: base.getParameters())
+            builder.parameter(p);
+        builder.description(base.getDescription());
+        if (base instanceof EffectorWithBody)
+            builder.impl(((EffectorWithBody<T>) base).getBody());
+        return builder;
+    }
+
+    /** as {@link #invocation(Entity, Effector, Map)} but convenience for passing a {@link ConfigBag} */
+    public static <T> TaskAdaptable<T> invocation(Entity entity, Effector<T> eff, ConfigBag parameters) {
+        return invocation(entity, eff, parameters==null ? ImmutableMap.of() : parameters.getAllConfig());
+    }
+    
+    /** returns an unsubmitted task which invokes the given effector; use {@link Entities#invokeEffector(EntityLocal, Entity, Effector, Map)} for a submitted variant */
+    public static <T> TaskAdaptable<T> invocation(Entity entity, Effector<T> eff, @Nullable Map<?,?> parameters) {
+        @SuppressWarnings("unchecked")
+        Effector<T> eff2 = (Effector<T>) ((EntityInternal)entity).getEffector(eff.getName());
+        if (log.isTraceEnabled()) {
+            Object eff1Body = (eff instanceof EffectorWithBody<?> ? ((EffectorWithBody<?>) eff).getBody() : "bodyless");
+            String message = String.format("Invoking %s/%s on entity %s", eff, eff1Body, entity);
+            if (eff != eff2) {
+                Object eff2Body = (eff2 instanceof EffectorWithBody<?> ? ((EffectorWithBody<?>) eff2).getBody() : "bodyless");
+                message += String.format(" (actually %s/%s)", eff2, eff2Body);
+            }
+            log.trace(message);
+        }
+        if (eff2 != null) {
+            if (eff2 != eff) {
+                if (eff2 instanceof EffectorWithBody) {
+                    log.debug("Replacing invocation of {} on {} with {} which is the impl defined at that entity", new Object[] { eff, entity, eff2 });
+                    return ((EffectorWithBody<T>)eff2).getBody().newTask(entity, eff2, ConfigBag.newInstance().putAll(parameters));
+                } else {
+                    log.warn("Effector {} defined on {} has no body; invoking caller-supplied {} instead", new Object[] { eff2, entity, eff });
+                }
+            }
+        } else {
+            log.debug("Effector {} does not exist on {}; attempting to invoke anyway", new Object[] { eff, entity });
+        }
+        
+        if (eff instanceof EffectorWithBody) {
+            return ((EffectorWithBody<T>)eff).getBody().newTask(entity, eff, ConfigBag.newInstance().putAll(parameters));
+        }
+        
+        throw new UnsupportedOperationException("No implementation registered for effector "+eff+" on "+entity);
+    }    
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public static <V> ParameterType<V> asParameterType(ConfigKey<V> key) {
+        return key.hasDefaultValue()
+            ? new BasicParameterType<V>(key.getName(), (Class)key.getType(), key.getDescription(), key.getDefaultValue())
+            : new BasicParameterType<V>(key.getName(), (Class)key.getType(), key.getDescription());
+    }
+    
+    public static <V> ConfigKey<V> asConfigKey(ParameterType<V> paramType) {
+        return ConfigKeys.newConfigKey(paramType.getParameterClass(), paramType.getName(), paramType.getDescription(), paramType.getDefaultValue());
+    }
+
+    /** returns an unsubmitted task which will invoke the given effector on the given entities;
+     * return type is Task<List<T>> (but haven't put in the blood sweat toil and tears to make the generics work) */
+    public static TaskAdaptable<List<?>> invocation(Effector<?> eff, Map<?,?> params, Iterable<? extends Entity> entities) {
+        List<TaskAdaptable<?>> tasks = new ArrayList<TaskAdaptable<?>>();
+        for (Entity e: entities) tasks.add(invocation(e, eff, params));
+        return Tasks.parallel("invoking "+eff+" on "+tasks.size()+" node"+(Strings.s(tasks.size())), tasks.toArray(new TaskAdaptable[tasks.size()]));
+    }
+
+    /** returns an unsubmitted task which will invoke the given effector on the given entities
+     * (this form of method is a convenience for {@link #invocation(Effector, Map, Iterable)}) */
+    public static TaskAdaptable<List<?>> invocation(Effector<?> eff, MutableMap<?, ?> params, Entity ...entities) {
+        return invocation(eff, params, Arrays.asList(entities));
+    }
+    
+    public static boolean sameSignature(Effector<?> e1, Effector<?> e2) {
+        return Objects.equal(e1.getName(), e2.getName()) &&
+                Objects.equal(e1.getParameters(), e2.getParameters()) &&
+                Objects.equal(e1.getReturnType(), e2.getReturnType());
+    }
+    
+    // TODO sameSignatureAndBody
+    
+    public static boolean sameInstance(Effector<?> e1, Effector<?> e2) {
+        return e1 == e2;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/effector/ExplicitEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/ExplicitEffector.java b/core/src/main/java/org/apache/brooklyn/core/effector/ExplicitEffector.java
new file mode 100644
index 0000000..65c1f0c
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/ExplicitEffector.java
@@ -0,0 +1,74 @@
+/*
+ * 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.core.effector;
+
+import groovy.lang.Closure;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.api.effector.ParameterType;
+import org.apache.brooklyn.api.entity.Entity;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+
+public abstract class ExplicitEffector<I,T> extends AbstractEffector<T> {
+    public ExplicitEffector(String name, Class<T> type, String description) {
+        this(name, type, ImmutableList.<ParameterType<?>>of(), description);
+    }
+    public ExplicitEffector(String name, Class<T> type, List<ParameterType<?>> parameters, String description) {
+        super(name, type, parameters, description);
+    }
+
+    public T call(Entity entity, Map parameters) {
+        return invokeEffector((I) entity, (Map<String,?>)parameters );
+    }
+
+    public abstract T invokeEffector(I trait, Map<String,?> parameters);
+    
+    /** convenience to create an effector supplying a closure; annotations are preferred,
+     * and subclass here would be failback, but this is offered as 
+     * workaround for bug GROOVY-5122, as discussed in test class CanSayHi 
+     */
+    public static <I,T> ExplicitEffector<I,T> create(String name, Class<T> type, List<ParameterType<?>> parameters, String description, Closure body) {
+        return new ExplicitEffectorFromClosure<I,T>(name, type, parameters, description, body);
+    }
+    
+    private static class ExplicitEffectorFromClosure<I,T> extends ExplicitEffector<I,T> {
+        private static final long serialVersionUID = -5771188171702382236L;
+        final Closure<T> body;
+        public ExplicitEffectorFromClosure(String name, Class<T> type, List<ParameterType<?>> parameters, String description, Closure<T> body) {
+            super(name, type, parameters, description);
+            this.body = body;
+        }
+        public T invokeEffector(I trait, Map<String,?> parameters) { return body.call(trait, parameters); }
+        
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(super.hashCode(), body);
+        }
+        
+        @Override
+        public boolean equals(Object other) {
+            return super.equals(other) && Objects.equal(body, ((ExplicitEffectorFromClosure<?,?>)other).body);
+        }
+        
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/core/effector/MethodEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/MethodEffector.java b/core/src/main/java/org/apache/brooklyn/core/effector/MethodEffector.java
new file mode 100644
index 0000000..ad53adb
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/MethodEffector.java
@@ -0,0 +1,180 @@
+/*
+ * 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.core.effector;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.effector.ParameterType;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.annotation.EffectorParam;
+import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.core.mgmt.internal.EffectorUtils;
+import org.apache.brooklyn.util.core.flags.TypeCoercions;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.groovy.GroovyJavaMethods;
+import org.codehaus.groovy.runtime.MethodClosure;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+
+/** concrete class for providing an Effector implementation that gets its information from annotations on a method;
+ * see Effector*Test for usage example.
+ * <p>
+ * note that the method must be on an interface in order for it to be remoted, with the current implementation.
+ * see comments in {@link #call(Entity, Map)} for more details.
+ */
+public class MethodEffector<T> extends AbstractEffector<T> {
+
+    private static final long serialVersionUID = 6989688364011965968L;
+    private static final Logger log = LoggerFactory.getLogger(MethodEffector.class);
+    
+    @SuppressWarnings("rawtypes")
+    public static Effector<?> create(Method m) {
+        return new MethodEffector(m);
+    }
+    
+    protected static class AnnotationsOnMethod {
+        final Class<?> clazz;
+        final String name;
+        final String description;
+        final Class<?> returnType;
+        final List<ParameterType<?>> parameters;
+
+        public AnnotationsOnMethod(Class<?> clazz, String methodName) {
+            this(clazz, inferBestMethod(clazz, methodName));
+        }
+
+        public AnnotationsOnMethod(Class<?> clazz, Method method) {
+            this.clazz = clazz;
+            this.name = method.getName();
+            this.returnType = method.getReturnType();
+
+            // Get the description
+            org.apache.brooklyn.core.annotation.Effector effectorAnnotation = method.getAnnotation(org.apache.brooklyn.core.annotation.Effector.class);
+            description = (effectorAnnotation != null) ? effectorAnnotation.description() : null;
+
+            // Get the parameters
+            parameters = Lists.newArrayList();
+            int numParameters = method.getParameterTypes().length;
+            for (int i = 0; i < numParameters; i++) {
+                parameters.add(toParameterType(method, i));
+            }
+        }
+
+        @SuppressWarnings({ "rawtypes", "unchecked" })
+        protected static ParameterType<?> toParameterType(Method method, int paramIndex) {
+            Annotation[] anns = method.getParameterAnnotations()[paramIndex];
+            Class<?> type = method.getParameterTypes()[paramIndex];
+            EffectorParam paramAnnotation = findAnnotation(anns, EffectorParam.class);
+
+            // TODO if blank, could do "param"+(i+1); would that be better?
+            // TODO this will now give "" if name is blank, rather than previously null. Is that ok?!
+            String name = (paramAnnotation != null) ? paramAnnotation.name() : null;
+
+            String paramDescription = (paramAnnotation == null || EffectorParam.MAGIC_STRING_MEANING_NULL.equals(paramAnnotation.description())) ? null : paramAnnotation.description();
+            String description = (paramDescription != null) ? paramDescription : null;
+
+            String paramDefaultValue = (paramAnnotation == null || EffectorParam.MAGIC_STRING_MEANING_NULL.equals(paramAnnotation.defaultValue())) ? null : paramAnnotation.defaultValue();
+            Object defaultValue = (paramDefaultValue != null) ? TypeCoercions.coerce(paramDefaultValue, type) : null;
+
+            return new BasicParameterType(name, type, description, defaultValue);
+        }
+        
+        @SuppressWarnings("unchecked")
+        protected static <T extends Annotation> T findAnnotation(Annotation[] anns, Class<T> type) {
+            for (Annotation ann : anns) {
+                if (type.isInstance(ann)) return (T) ann;
+            }
+            return null;
+        }
+        
+        protected static Method inferBestMethod(Class<?> clazz, String methodName) {
+            Method best = null;
+            for (Method it : clazz.getMethods()) { 
+                if (it.getName().equals(methodName)) {
+                    if (best==null || best.getParameterTypes().length < it.getParameterTypes().length) best=it;
+                }
+            }
+            if (best==null) {
+                throw new IllegalStateException("Cannot find method "+methodName+" on "+clazz.getCanonicalName());
+            }
+            return best;
+        }
+    }
+
+    /** Defines a new effector whose details are supplied as annotations on the given type and method name */
+    public MethodEffector(Class<?> whereEffectorDefined, String methodName) {
+        this(new AnnotationsOnMethod(whereEffectorDefined, methodName), null);
+    }
+
+    public MethodEffector(Method method) {
+        this(new AnnotationsOnMethod(method.getDeclaringClass(), method), null);
+    }
+
+    public MethodEffector(MethodClosure mc) {
+        this(new AnnotationsOnMethod((Class<?>)mc.getDelegate(), mc.getMethod()), null);
+    }
+
+    @SuppressWarnings("unchecked")
+    protected MethodEffector(AnnotationsOnMethod anns, String description) {
+        super(anns.name, (Class<T>)anns.returnType, anns.parameters, GroovyJavaMethods.<String>elvis(description, anns.description));
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public T call(Entity entity, Map parameters) {
+        Object[] parametersArray = EffectorUtils.prepareArgsForEffector(this, parameters);
+        if (entity instanceof AbstractEntity) {
+            return EffectorUtils.invokeMethodEffector(entity, this, parametersArray);
+        } else {
+            // we are dealing with a proxy here
+            // this implementation invokes the method on the proxy
+            // (requiring it to be on the interface)
+            // and letting the proxy deal with the remoting / runAtEntity;
+            // alternatively we could create the task here and pass it to runAtEntity;
+            // the latter may allow us to simplify/remove a lot of the stuff from 
+            // EffectorUtils and possibly Effectors and Entities
+            
+            // TODO Should really find method with right signature, rather than just the right args.
+            // TODO prepareArgs can miss things out that have "default values"! Code below will probably fail if that happens.
+            Method[] methods = entity.getClass().getMethods();
+            for (Method method : methods) {
+                if (method.getName().equals(getName())) {
+                    if (parametersArray.length == method.getParameterTypes().length) {
+                        try {
+                            return (T) method.invoke(entity, parametersArray);
+                        } catch (Exception e) {
+                            // exception handled by the proxy invocation (which leads to EffectorUtils.invokeEffectorMethod...)
+                            throw Exceptions.propagate(e);
+                        }
+                    }
+                }
+            }
+            String msg = "Could not find method for effector "+getName()+" with "+parametersArray.length+" parameters on "+entity;
+            log.warn(msg+" (throwing); available methods are: "+Arrays.toString(methods));
+            throw new IllegalStateException(msg);
+        }
+    }
+    
+}


[16/36] incubator-brooklyn git commit: Rename o.a.b.sensor.core to o.a.b.core.sensor

Posted by he...@apache.org.
Rename o.a.b.sensor.core to o.a.b.core.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/2a78e273
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/2a78e273
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/2a78e273

Branch: refs/heads/master
Commit: 2a78e273dae0caf2e7a3b791f365d7c839a9b20b
Parents: 8dbb0e4
Author: Aled Sage <al...@gmail.com>
Authored: Wed Aug 19 22:42:32 2015 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Wed Aug 19 22:48:55 2015 +0100

----------------------------------------------------------------------
 .../apache/brooklyn/core/config/ConfigKeys.java |   8 +-
 .../brooklyn/core/effector/AddSensor.java       |   2 +-
 .../brooklyn/core/entity/AbstractEntity.java    |   8 +-
 .../apache/brooklyn/core/entity/Attributes.java |  10 +-
 .../core/entity/BrooklynConfigKeys.java         |   4 +-
 .../apache/brooklyn/core/entity/Entities.java   |   2 +-
 .../brooklyn/core/entity/EntityTasks.java       |   2 +-
 .../brooklyn/core/entity/trait/Changeable.java  |   4 +-
 .../core/location/dynamic/LocationOwner.java    |   4 +-
 .../core/mgmt/persist/XmlMementoSerializer.java |   2 +-
 .../mgmt/rebind/dto/BasicEntityMemento.java     |   2 +-
 .../brooklyn/core/sensor/AttributeMap.java      | 202 +++++
 .../sensor/AttributeSensorAndConfigKey.java     | 147 ++++
 .../core/sensor/BasicAttributeSensor.java       |  62 ++
 .../BasicAttributeSensorAndConfigKey.java       | 114 +++
 .../core/sensor/BasicNotificationSensor.java    |  36 +
 .../brooklyn/core/sensor/BasicSensor.java       | 114 +++
 .../brooklyn/core/sensor/BasicSensorEvent.java  | 112 +++
 .../core/sensor/DependentConfiguration.java     | 823 +++++++++++++++++++
 .../brooklyn/core/sensor/HttpRequestSensor.java |  96 +++
 .../sensor/PortAttributeSensorAndConfigKey.java | 141 ++++
 .../apache/brooklyn/core/sensor/Sensors.java    | 164 ++++
 .../brooklyn/core/sensor/StaticSensor.java      |  72 ++
 ...platedStringAttributeSensorAndConfigKey.java |  66 ++
 .../core/server/entity/BrooklynMetrics.java     |   4 +-
 .../brooklyn/entity/group/AbstractGroup.java    |   2 +-
 .../brooklyn/entity/group/DynamicCluster.java   |   6 +-
 .../brooklyn/entity/group/DynamicFabric.java    |   2 +-
 .../brooklyn/entity/group/DynamicGroup.java     |   2 +-
 .../entity/group/DynamicMultiGroup.java         |   2 +-
 .../brooklyn/entity/stock/DelegateEntity.java   |   4 +-
 .../winrm/AdvertiseWinrmLoginPolicy.java        |   2 +-
 .../brooklyn/sensor/core/AttributeMap.java      | 202 -----
 .../core/AttributeSensorAndConfigKey.java       | 147 ----
 .../sensor/core/BasicAttributeSensor.java       |  62 --
 .../core/BasicAttributeSensorAndConfigKey.java  | 114 ---
 .../sensor/core/BasicNotificationSensor.java    |  36 -
 .../brooklyn/sensor/core/BasicSensor.java       | 114 ---
 .../brooklyn/sensor/core/BasicSensorEvent.java  | 112 ---
 .../sensor/core/DependentConfiguration.java     | 823 -------------------
 .../brooklyn/sensor/core/HttpRequestSensor.java |  96 ---
 .../core/PortAttributeSensorAndConfigKey.java   | 141 ----
 .../apache/brooklyn/sensor/core/Sensors.java    | 164 ----
 .../brooklyn/sensor/core/StaticSensor.java      |  72 --
 ...platedStringAttributeSensorAndConfigKey.java |  66 --
 .../sensor/enricher/AbstractTransformer.java    |   2 +-
 .../AbstractTypeTransformingEnricher.java       |   2 +-
 .../sensor/enricher/AddingEnricher.java         |   2 +-
 .../brooklyn/sensor/enricher/Combiner.java      |   2 +-
 .../apache/brooklyn/sensor/enricher/Joiner.java |   2 +-
 .../sensor/feed/ConfigToAttributes.java         |   4 +-
 .../apache/brooklyn/sensor/feed/FeedConfig.java |   2 +-
 .../windows/WindowsPerformanceCounterFeed.java  |   2 +-
 .../brooklyn/util/core/flags/TypeCoercions.java |   2 +-
 .../util/core/text/TemplateProcessor.java       |   4 +-
 ...apListAndOtherStructuredConfigKeyTest.groovy |   2 +-
 .../brooklyn/core/entity/AttributeMapTest.java  |   4 +-
 .../brooklyn/core/entity/AttributeTest.java     |   2 +-
 .../entity/ConfigEntityInheritanceTest.java     |   4 +-
 .../core/entity/DependentConfigurationTest.java |   2 +-
 .../core/entity/EntitySubscriptionTest.java     |   2 +-
 .../brooklyn/core/entity/EntityTypeTest.java    |   4 +-
 .../brooklyn/core/entity/hello/HelloEntity.java |   4 +-
 .../core/entity/hello/LocalEntitiesTest.java    |   4 +-
 .../core/entity/internal/ConfigMapTest.java     |   2 +-
 .../EntityConfigMapUsageLegacyTest.java         |   2 +-
 .../internal/EntityConfigMapUsageTest.java      |   2 +-
 .../entity/lifecycle/ServiceStateLogicTest.java |   2 +-
 .../core/location/TestPortSupplierLocation.java |   2 +-
 .../access/PortForwardManagerRebindTest.java    |   2 +-
 .../internal/EntityExecutionManagerTest.java    |   2 +-
 .../mgmt/rebind/RebindCatalogEntityTest.java    |   2 +-
 .../core/mgmt/rebind/RebindEnricherTest.java    |   2 +-
 .../core/mgmt/rebind/RebindEntityTest.java      |   8 +-
 .../core/mgmt/rebind/RebindFeedTest.java        |   2 +-
 .../core/policy/basic/PolicyConfigTest.java     |   2 +-
 .../policy/basic/PolicySubscriptionTest.java    |   2 +-
 .../core/sensor/HttpRequestSensorTest.java      |  85 ++
 .../brooklyn/core/sensor/StaticSensorTest.java  |  55 ++
 .../core/test/entity/TestApplication.java       |   2 +-
 .../brooklyn/core/test/entity/TestEntity.java   |   4 +-
 .../brooklyn/entity/group/DynamicGroupTest.java |   2 +-
 .../entity/group/DynamicMultiGroupTest.java     |   2 +-
 .../brooklyn/entity/stock/DataEntityTest.java   |   2 +-
 .../sensor/core/HttpRequestSensorTest.java      |  85 --
 .../brooklyn/sensor/core/StaticSensorTest.java  |  55 --
 ...stomAggregatingEnricherDeprecatedTest.groovy |   2 +-
 .../enricher/CustomAggregatingEnricherTest.java |   2 +-
 .../brooklyn/sensor/enricher/EnrichersTest.java |   2 +-
 ...SensorPropagatingEnricherDeprecatedTest.java |   2 +-
 .../enricher/SensorPropagatingEnricherTest.java |   4 +-
 .../TransformingEnricherDeprecatedTest.groovy   |   2 +-
 .../enricher/TransformingEnricherTest.java      |   2 +-
 .../YamlRollingTimeWindowMeanEnricherTest.java  |   4 +-
 .../YamlTimeWeightedDeltaEnricherTest.java      |   4 +-
 .../sensor/feed/ConfigToAttributesTest.java     |   4 +-
 .../sensor/feed/function/FunctionFeedTest.java  |   2 +-
 .../feed/http/HttpFeedIntegrationTest.java      |   2 +-
 .../brooklyn/sensor/feed/http/HttpFeedTest.java |   2 +-
 .../feed/shell/ShellFeedIntegrationTest.java    |   2 +-
 .../sensor/feed/ssh/SshFeedIntegrationTest.java |   2 +-
 .../WindowsPerformanceCounterFeedLiveTest.java  |   2 +-
 .../WindowsPerformanceCounterFeedTest.java      |   2 +-
 .../brooklyn/util/core/task/TasksTest.java      |   2 +-
 .../util/core/text/TemplateProcessorTest.java   |   2 +-
 .../brooklyn/demo/GlobalWebFabricExample.java   |   2 +-
 .../brooklyn/demo/CumulusRDFApplication.java    |   2 +-
 .../brooklyn/demo/NodeJsTodoApplication.java    |   4 +-
 .../demo/WebClusterDatabaseExample.java         |   6 +-
 .../demo/WebClusterDatabaseExampleApp.java      |   6 +-
 .../demo/WebClusterDatabaseExampleGroovy.groovy |   4 +-
 .../policy/jclouds/os/CreateUserPolicy.java     |   2 +-
 .../policy/autoscaling/AutoScalerPolicy.java    |   2 +-
 .../policy/enricher/HttpLatencyDetector.java    |   2 +-
 .../policy/followthesun/FollowTheSunPool.java   |   2 +-
 .../policy/ha/ConnectionFailureDetector.java    |   2 +-
 .../apache/brooklyn/policy/ha/HASensors.java    |   2 +-
 .../policy/ha/ServiceFailureDetector.java       |   2 +-
 .../brooklyn/policy/ha/ServiceReplacer.java     |   2 +-
 .../brooklyn/policy/ha/ServiceRestarter.java    |   2 +-
 .../policy/ha/SshMachineFailureDetector.java    |   2 +-
 .../loadbalancing/BalanceableContainer.java     |   2 +-
 .../loadbalancing/BalanceableWorkerPool.java    |   2 +-
 .../brooklyn/policy/loadbalancing/Movable.java  |   2 +-
 .../autoscaling/AutoScalerPolicyMetricTest.java |   4 +-
 .../autoscaling/AutoScalerPolicyRebindTest.java |   4 +-
 .../AutoScalerPolicyReconfigurationTest.java    |   2 +-
 .../autoscaling/AutoScalerPolicyTest.java       |   2 +-
 .../policy/enricher/DeltaEnrichersTests.groovy  |   2 +-
 .../enricher/HttpLatencyDetectorTest.java       |   2 +-
 .../policy/enricher/RebindEnricherTest.java     |   2 +-
 .../enricher/RollingMeanEnricherTest.groovy     |   2 +-
 .../RollingTimeWindowMeanEnricherTest.groovy    |   2 +-
 .../enricher/TimeFractionDeltaEnricherTest.java |   4 +-
 .../AbstractLoadBalancingPolicyTest.java        |   2 +-
 .../policy/loadbalancing/MockItemEntity.java    |   2 +-
 .../entity/database/derby/DerbyDatabase.java    |   4 +-
 .../entity/database/derby/DerbySchema.java      |   2 +-
 .../postgresql/PostgreSqlNodeSaltImpl.java      |   2 +-
 .../apache/brooklyn/entity/salt/SaltConfig.java |   2 +-
 .../brooklyn/entity/salt/SaltStackMaster.java   |   4 +-
 .../monitoring/zabbix/ZabbixMonitored.java      |   4 +-
 .../entity/monitoring/zabbix/ZabbixServer.java  |   2 +-
 .../nosql/hazelcast/HazelcastCluster.java       |   4 +-
 .../entity/nosql/hazelcast/HazelcastNode.java   |   6 +-
 .../nosql/infinispan/Infinispan5Server.java     |   4 +-
 .../entity/brooklynnode/BrooklynCluster.java    |   2 +-
 .../brooklynnode/BrooklynEntityMirror.java      |   2 +-
 .../brooklynnode/BrooklynEntityMirrorImpl.java  |   2 +-
 .../entity/brooklynnode/BrooklynNode.java       |  10 +-
 .../entity/java/JmxAttributeSensor.java         |   4 +-
 .../brooklyn/entity/java/UsesJavaMXBeans.java   |   4 +-
 .../apache/brooklyn/entity/java/UsesJmx.java    |   6 +-
 .../brooklyn/entity/java/VanillaJavaApp.java    |   2 +-
 .../entity/machine/MachineAttributes.java       |   2 +-
 .../entity/machine/pool/ServerPool.java         |   2 +-
 .../entity/machine/pool/ServerPoolImpl.java     |   2 +-
 .../AbstractSoftwareProcessWinRmDriver.java     |   2 +-
 .../software/base/AbstractVanillaProcess.java   |   2 +-
 .../entity/software/base/SameServerEntity.java  |   2 +-
 .../entity/software/base/SoftwareProcess.java   |   4 +-
 .../software/base/SoftwareProcessImpl.java      |   2 +-
 .../software/base/VanillaWindowsProcess.java    |   2 +-
 .../brooklyn/sensor/ssh/SshCommandSensor.java   |   2 +-
 .../winrm/WindowsPerformanceCounterSensors.java |   2 +-
 .../entity/brooklynnode/MockBrooklynNode.java   |   2 +-
 .../brooklyn/entity/java/EntityPollingTest.java |   2 +-
 .../entity/java/VanillaJavaAppRebindTest.java   |   2 +-
 .../base/SoftwareProcessEntityLatchTest.java    |   2 +-
 .../base/SoftwareProcessEntityTest.java         |   2 +-
 .../MachineLifecycleEffectorTasksTest.java      |   4 +-
 .../PortAttributeSensorAndConfigKeyTest.java    |   2 +-
 .../test/ssh/SshCommandIntegrationTest.java     |   2 +-
 .../brooklyn/sensor/feed/jmx/JmxFeedTest.java   |   6 +-
 .../sensor/feed/jmx/RebindJmxFeedTest.java      |   2 +-
 .../entity/database/DatastoreMixins.java        |   2 +-
 .../entity/database/crate/CrateNode.java        |   8 +-
 .../entity/database/mariadb/MariaDbNode.java    |   8 +-
 .../entity/database/mysql/MySqlCluster.java     |   4 +-
 .../entity/database/mysql/MySqlClusterImpl.java |   4 +-
 .../entity/database/mysql/MySqlNode.java        |   8 +-
 .../database/postgresql/PostgreSqlNode.java     |   4 +-
 .../postgresql/PostgreSqlSshDriver.java         |   2 +-
 .../entity/database/rubyrep/RubyRepNode.java    |   6 +-
 .../database/rubyrep/RubyRepNodeImpl.java       |   2 +-
 .../entity/messaging/MessageBroker.java         |   2 +-
 .../apache/brooklyn/entity/messaging/Queue.java |   4 +-
 .../apache/brooklyn/entity/messaging/Topic.java |   2 +-
 .../messaging/activemq/ActiveMQBroker.java      |   8 +-
 .../entity/messaging/amqp/AmqpExchange.java     |   2 +-
 .../entity/messaging/amqp/AmqpServer.java       |   4 +-
 .../brooklyn/entity/messaging/kafka/Kafka.java  |   2 +-
 .../entity/messaging/kafka/KafkaBroker.java     |   4 +-
 .../entity/messaging/kafka/KafkaCluster.java    |   4 +-
 .../entity/messaging/kafka/KafkaZooKeeper.java  |   2 +-
 .../entity/messaging/qpid/QpidBroker.java       |   4 +-
 .../entity/messaging/rabbit/RabbitBroker.java   |   6 +-
 .../brooklyn/entity/messaging/storm/Storm.java  |   6 +-
 .../entity/messaging/storm/StormSshDriver.java  |   2 +-
 .../entity/zookeeper/ZooKeeperEnsemble.java     |   4 +-
 .../entity/zookeeper/ZooKeeperNode.java         |   6 +-
 .../storm/StormAbstractCloudLiveTest.java       |   2 +-
 .../entity/monitoring/monit/MonitNode.java      |   6 +-
 .../monitoring/monit/MonitIntegrationTest.java  |   2 +-
 .../entity/network/bind/BindDnsServer.java      |   4 +-
 .../network/bind/PrefixAndIdEnricher.java       |   2 +-
 .../nosql/cassandra/CassandraDatacenter.java    |   4 +-
 .../entity/nosql/cassandra/CassandraNode.java   |   6 +-
 .../nosql/cassandra/CassandraNodeImpl.java      |   4 +-
 .../nosql/cassandra/CassandraNodeSshDriver.java |   2 +-
 .../nosql/couchbase/CouchbaseCluster.java       |   2 +-
 .../nosql/couchbase/CouchbaseClusterImpl.java   |   2 +-
 .../entity/nosql/couchbase/CouchbaseNode.java   |   6 +-
 .../nosql/couchbase/CouchbaseNodeSshDriver.java |   2 +-
 .../nosql/couchbase/CouchbaseSyncGateway.java   |   6 +-
 .../CouchbaseSyncGatewaySshDriver.java          |   2 +-
 .../entity/nosql/couchdb/CouchDBCluster.java    |   4 +-
 .../entity/nosql/couchdb/CouchDBNode.java       |   2 +-
 .../elasticsearch/ElasticSearchCluster.java     |   2 +-
 .../nosql/elasticsearch/ElasticSearchNode.java  |   8 +-
 .../nosql/mongodb/AbstractMongoDBServer.java    |   6 +-
 .../nosql/mongodb/MongoDBClientSshDriver.java   |   2 +-
 .../entity/nosql/mongodb/MongoDBReplicaSet.java |   2 +-
 .../entity/nosql/mongodb/MongoDBServer.java     |   4 +-
 .../sharding/CoLocatedMongoDBRouter.java        |   2 +-
 .../sharding/CoLocatedMongoDBRouterImpl.java    |   2 +-
 .../sharding/MongoDBConfigServerCluster.java    |   2 +-
 .../nosql/mongodb/sharding/MongoDBRouter.java   |   2 +-
 .../mongodb/sharding/MongoDBRouterCluster.java  |   2 +-
 .../sharding/MongoDBShardedDeployment.java      |   2 +-
 .../sharding/MongoDBShardedDeploymentImpl.java  |   2 +-
 .../entity/nosql/redis/RedisClusterImpl.java    |   2 +-
 .../brooklyn/entity/nosql/redis/RedisStore.java |   6 +-
 .../brooklyn/entity/nosql/riak/RiakCluster.java |   2 +-
 .../entity/nosql/riak/RiakClusterImpl.java      |   2 +-
 .../brooklyn/entity/nosql/riak/RiakNode.java    |   6 +-
 .../entity/nosql/riak/RiakNodeImpl.java         |   2 +-
 .../brooklyn/entity/nosql/solr/SolrServer.java  |   4 +-
 .../cassandra/CassandraNodeIntegrationTest.java |   2 +-
 .../entity/osgi/karaf/KarafContainer.java       |   6 +-
 .../entity/dns/AbstractGeoDnsService.java       |   2 +-
 .../dns/geoscaling/GeoscalingDnsService.java    |   2 +-
 .../entity/proxy/AbstractController.java        |   2 +-
 .../brooklyn/entity/proxy/LoadBalancer.java     |   6 +-
 .../entity/proxy/nginx/NginxController.java     |   4 +-
 .../brooklyn/entity/proxy/nginx/UrlMapping.java |   2 +-
 .../webapp/ControlledDynamicWebAppCluster.java  |   4 +-
 .../entity/webapp/DynamicWebAppCluster.java     |   2 +-
 .../entity/webapp/DynamicWebAppFabric.java      |   2 +-
 .../entity/webapp/JavaWebAppService.java        |   2 +-
 .../entity/webapp/WebAppServiceConstants.java   |   6 +-
 .../entity/webapp/WebAppServiceMetrics.java     |   8 +-
 .../entity/webapp/jboss/JBoss6Server.java       |   2 +-
 .../entity/webapp/jboss/JBoss7Server.java       |   8 +-
 .../entity/webapp/jetty/Jetty6Server.java       |   4 +-
 .../entity/webapp/tomcat/Tomcat8Server.java     |   2 +-
 .../entity/webapp/tomcat/TomcatServer.java      |   6 +-
 .../brooklyn/entity/proxy/StubAppServer.java    |   2 +-
 .../nginx/NginxHttpsSslIntegrationTest.java     |   2 +-
 .../app/ClusterWebServerDatabaseSample.java     |   6 +-
 .../spi/dsl/methods/BrooklynDslCommon.java      |   2 +-
 .../brooklyn/spi/dsl/methods/DslComponent.java  |   4 +-
 .../camp/brooklyn/DslAndRebindYamlTest.java     |   2 +-
 .../EnrichersSlightlySimplerYamlTest.java       |   2 +-
 .../camp/brooklyn/EntitiesYamlTest.java         |   2 +-
 .../TestSensorAndEffectorInitializer.java       |   2 +-
 .../brooklyn/VanillaBashNetcatYamlTest.java     |   2 +-
 .../brooklyn/qa/load/SimulatedTheeTierApp.java  |   4 +-
 .../qa/longevity/webcluster/WebClusterApp.java  |   2 +-
 .../rest/resources/ApplicationResource.java     |   2 +-
 .../brooklyn/rest/resources/SensorResource.java |   2 +-
 .../brooklyn/rest/domain/SensorSummaryTest.java |   2 +-
 .../rest/resources/DescendantsTest.java         |   2 +-
 .../rest/resources/SensorResourceTest.java      |   2 +-
 .../testing/mocks/RestMockSimpleEntity.java     |   2 +-
 275 files changed, 2667 insertions(+), 2667 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/config/ConfigKeys.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/config/ConfigKeys.java b/core/src/main/java/org/apache/brooklyn/core/config/ConfigKeys.java
index 167e208..df03c29 100644
--- a/core/src/main/java/org/apache/brooklyn/core/config/ConfigKeys.java
+++ b/core/src/main/java/org/apache/brooklyn/core/config/ConfigKeys.java
@@ -24,10 +24,10 @@ import javax.annotation.Nonnull;
 
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.BasicConfigKey.BasicConfigKeyOverwriting;
-import org.apache.brooklyn.sensor.core.AttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.TemplatedStringAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.TemplatedStringAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.text.Strings;
 import org.apache.brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java b/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java
index 3c08831..d35068f 100644
--- a/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java
@@ -26,7 +26,7 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.javalang.Boxing;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java b/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
index ea6bda7..994961c 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
@@ -77,10 +77,10 @@ import org.apache.brooklyn.core.objs.AbstractBrooklynObject;
 import org.apache.brooklyn.core.objs.AbstractEntityAdjunct;
 import org.apache.brooklyn.core.objs.AbstractEntityAdjunct.AdjunctTagSupport;
 import org.apache.brooklyn.core.policy.AbstractPolicy;
-import org.apache.brooklyn.sensor.core.AttributeMap;
-import org.apache.brooklyn.sensor.core.AttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.BasicNotificationSensor;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.AttributeMap;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
 import org.apache.brooklyn.sensor.feed.AbstractFeed;
 import org.apache.brooklyn.sensor.feed.ConfigToAttributes;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/entity/Attributes.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/Attributes.java b/core/src/main/java/org/apache/brooklyn/core/entity/Attributes.java
index e585e5d..80ed765 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/Attributes.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/Attributes.java
@@ -27,11 +27,11 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.Sensor;
 import org.apache.brooklyn.core.config.render.RendererHints;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.BasicNotificationSensor;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.util.net.UserAndHostAndPort;
 
 import com.google.common.annotations.Beta;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/entity/BrooklynConfigKeys.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/BrooklynConfigKeys.java b/core/src/main/java/org/apache/brooklyn/core/entity/BrooklynConfigKeys.java
index 716f934..cedccb8 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/BrooklynConfigKeys.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/BrooklynConfigKeys.java
@@ -27,9 +27,9 @@ import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.TemplatedStringAttributeSensorAndConfigKey;
 import org.apache.brooklyn.core.server.BrooklynServerConfig;
-import org.apache.brooklyn.sensor.core.AttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.TemplatedStringAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.internal.ssh.ShellTool;
 import org.apache.brooklyn.util.core.internal.ssh.SshTool;
 import org.apache.brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java b/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java
index ca561e1..c1a77ad 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java
@@ -77,7 +77,7 @@ import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.mgmt.internal.NonDeploymentManagementContext;
 import org.apache.brooklyn.core.objs.BrooklynObjectInternal;
 import org.apache.brooklyn.core.objs.proxy.EntityProxyImpl;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.core.config.ConfigBag;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/entity/EntityTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntityTasks.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntityTasks.java
index ba2992f..c4f383d 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/EntityTasks.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntityTasks.java
@@ -21,7 +21,7 @@ package org.apache.brooklyn.core.entity;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.util.collections.CollectionFunctionals;
 import org.apache.brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/entity/trait/Changeable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/trait/Changeable.java b/core/src/main/java/org/apache/brooklyn/core/entity/trait/Changeable.java
index d8fec0e..388eb17 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/trait/Changeable.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/trait/Changeable.java
@@ -20,8 +20,8 @@ package org.apache.brooklyn.core.entity.trait;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.sensor.core.BasicNotificationSensor;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
+import org.apache.brooklyn.core.sensor.Sensors;
 
 /**
  * A collection of entities that can change.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/location/dynamic/LocationOwner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/location/dynamic/LocationOwner.java b/core/src/main/java/org/apache/brooklyn/core/location/dynamic/LocationOwner.java
index 1d4d4c1..718b97e 100644
--- a/core/src/main/java/org/apache/brooklyn/core/location/dynamic/LocationOwner.java
+++ b/core/src/main/java/org/apache/brooklyn/core/location/dynamic/LocationOwner.java
@@ -26,8 +26,8 @@ import org.apache.brooklyn.api.location.LocationDefinition;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 import com.google.common.annotations.Beta;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java
index e1d704b..b232ce4 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java
@@ -59,7 +59,7 @@ import org.apache.brooklyn.core.mgmt.rebind.dto.BasicFeedMemento;
 import org.apache.brooklyn.core.mgmt.rebind.dto.BasicLocationMemento;
 import org.apache.brooklyn.core.mgmt.rebind.dto.BasicPolicyMemento;
 import org.apache.brooklyn.core.mgmt.rebind.dto.MutableBrooklynMemento;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
 import org.apache.brooklyn.util.core.xstream.XmlSerializer;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.text.Strings;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java
index 7da8441..7418813 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java
@@ -39,7 +39,7 @@ import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.config.Sanitizer;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.objs.BrooklynTypes;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.Sensors;
 
 import com.google.common.base.Objects.ToStringHelper;
 import com.google.common.collect.Lists;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/sensor/AttributeMap.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/AttributeMap.java b/core/src/main/java/org/apache/brooklyn/core/sensor/AttributeMap.java
new file mode 100644
index 0000000..b584f24
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/sensor/AttributeMap.java
@@ -0,0 +1,202 @@
+/*
+ * 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.core.sensor;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.BrooklynLogging;
+import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.util.core.flags.TypeCoercions;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+
+/**
+ * A {@link Map} of {@link Entity} attribute values.
+ */
+public final class AttributeMap implements Serializable {
+
+    private static final long serialVersionUID = -6834883734250888344L;
+
+    static final Logger log = LoggerFactory.getLogger(AttributeMap.class);
+
+    private static enum Marker {
+        NULL;
+    }
+    
+    private final AbstractEntity entity;
+
+    // Assumed to be something like a ConcurrentMap passed in.
+    private final Map<Collection<String>, Object> values;
+
+    /**
+     * Creates a new AttributeMap.
+     *
+     * @param entity the EntityLocal this AttributeMap belongs to.
+     * @throws IllegalArgumentException if entity is null
+     */
+    public AttributeMap(AbstractEntity entity, Map<Collection<String>, Object> storage) {
+        this.entity = checkNotNull(entity, "entity must be specified");
+        this.values = checkNotNull(storage, "storage map must not be null");
+    }
+
+    public Map<Collection<String>, Object> asRawMap() {
+        return ImmutableMap.copyOf(values);
+    }
+
+    public Map<String, Object> asMap() {
+        Map<String, Object> result = Maps.newLinkedHashMap();
+        for (Map.Entry<Collection<String>, Object> entry : values.entrySet()) {
+            String sensorName = Joiner.on('.').join(entry.getKey());
+            Object val = (isNull(entry.getValue())) ? null : entry.getValue();
+            result.put(sensorName, val);
+        }
+        return result;
+    }
+    
+    /**
+     * Updates the value.
+     *
+     * @param path the path to the value.
+     * @param newValue the new value
+     * @return the old value.
+     * @throws IllegalArgumentException if path is null or empty
+     */
+    // TODO path must be ordered(and legal to contain duplicates like "a.b.a"; list would be better
+    public <T> T update(Collection<String> path, T newValue) {
+        checkPath(path);
+
+        if (newValue == null) {
+            newValue = typedNull();
+        }
+
+        if (log.isTraceEnabled()) {
+            log.trace("setting sensor {}={} for {}", new Object[] {path, newValue, entity});
+        }
+
+        @SuppressWarnings("unchecked")
+        T oldValue = (T) values.put(path, newValue);
+        return (isNull(oldValue)) ? null : oldValue;
+    }
+
+    private void checkPath(Collection<String> path) {
+        Preconditions.checkNotNull(path, "path can't be null");
+        Preconditions.checkArgument(!path.isEmpty(), "path can't be empty");
+    }
+
+    public <T> T update(AttributeSensor<T> attribute, T newValue) {
+        T oldValue = updateWithoutPublishing(attribute, newValue);
+        entity.emitInternal(attribute, newValue);
+        return oldValue;
+    }
+    
+    public <T> T updateWithoutPublishing(AttributeSensor<T> attribute, T newValue) {
+        if (log.isTraceEnabled()) {
+            Object oldValue = getValue(attribute);
+            if (!Objects.equal(oldValue, newValue != null)) {
+                log.trace("setting attribute {} to {} (was {}) on {}", new Object[] {attribute.getName(), newValue, oldValue, entity});
+            } else {
+                log.trace("setting attribute {} to {} (unchanged) on {}", new Object[] {attribute.getName(), newValue, this});
+            }
+        }
+
+        T oldValue = (T) update(attribute.getNameParts(), newValue);
+        
+        return (isNull(oldValue)) ? null : oldValue;
+    }
+
+    /**
+     * Where atomicity is desired, the methods in this class synchronize on the {@link #values} map.
+     */
+    public <T> T modify(AttributeSensor<T> attribute, Function<? super T, Maybe<T>> modifier) {
+        synchronized (values) {
+            T oldValue = getValue(attribute);
+            Maybe<? extends T> newValue = modifier.apply(oldValue);
+
+            if (newValue.isPresent()) {
+                if (log.isTraceEnabled()) log.trace("modified attribute {} to {} (was {}) on {}", new Object[] {attribute.getName(), newValue, oldValue, entity});
+                return update(attribute, newValue.get());
+            } else {
+                if (log.isTraceEnabled()) log.trace("modified attribute {} unchanged; not emitting on {}", new Object[] {attribute.getName(), newValue, this});
+                return oldValue;
+            }
+        }
+    }
+
+    public void remove(AttributeSensor<?> attribute) {
+        BrooklynLogging.log(log, BrooklynLogging.levelDebugOrTraceIfReadOnly(entity),
+            "removing attribute {} on {}", attribute.getName(), entity);
+
+        remove(attribute.getNameParts());
+    }
+
+    // TODO path must be ordered(and legal to contain duplicates like "a.b.a"; list would be better
+    public void remove(Collection<String> path) {
+        checkPath(path);
+
+        if (log.isTraceEnabled()) {
+            log.trace("removing sensor {} for {}", new Object[] {path, entity});
+        }
+
+        values.remove(path);
+    }
+
+    /**
+     * Gets the value
+     *
+     * @param path the path of the value to get
+     * @return the value
+     * @throws IllegalArgumentException path is null or empty.
+     */
+    public Object getValue(Collection<String> path) {
+        // TODO previously this would return a map of the sub-tree if the path matched a prefix of a group of sensors, 
+        // or the leaf value if only one value. Arguably that is not required - what is/was the use-case?
+        // 
+        checkPath(path);
+        Object result = values.get(path);
+        return (isNull(result)) ? null : result;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T getValue(AttributeSensor<T> sensor) {
+        return (T) TypeCoercions.coerce(getValue(sensor.getNameParts()), sensor.getType());
+    }
+
+    @SuppressWarnings("unchecked")
+    private <T> T typedNull() {
+        return (T) Marker.NULL;
+    }
+    
+    private boolean isNull(Object t) {
+        return t == Marker.NULL;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/sensor/AttributeSensorAndConfigKey.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/AttributeSensorAndConfigKey.java b/core/src/main/java/org/apache/brooklyn/core/sensor/AttributeSensorAndConfigKey.java
new file mode 100644
index 0000000..940d949
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/sensor/AttributeSensorAndConfigKey.java
@@ -0,0 +1,147 @@
+/*
+ * 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.core.sensor;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.BasicConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
+import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
+import org.apache.brooklyn.util.core.flags.TypeCoercions;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.reflect.TypeToken;
+
+/**
+* A {@link Sensor} describing an attribute that can be configured with inputs that are used to derive the final value.
+* <p>
+* The {@link ConfigKey} will have the same name and description as the sensor but not necessarily the same type.
+* Conversion to set the sensor value from the config key must be supplied in a subclass.
+* <p>
+* {@link ConfigToAttributes#apply(EntityLocal, AttributeSensorAndConfigKey)} is useful to set the attribute from the sensor.
+*/
+public abstract class AttributeSensorAndConfigKey<ConfigType,SensorType> extends BasicAttributeSensor<SensorType> 
+        implements ConfigKey.HasConfigKey<ConfigType> {
+    private static final long serialVersionUID = -3103809215973264600L;
+    private static final Logger log = LoggerFactory.getLogger(AttributeSensorAndConfigKey.class);
+
+    private ConfigKey<ConfigType> configKey;
+
+    public AttributeSensorAndConfigKey(Class<ConfigType> configType, Class<SensorType> sensorType, String name) {
+        this(configType, sensorType, name, name, null);
+    }
+    
+    public AttributeSensorAndConfigKey(Class<ConfigType> configType, Class<SensorType> sensorType, String name, String description) {
+        this(TypeToken.of(configType), TypeToken.of(sensorType), name, description, null);
+    }
+    
+    public AttributeSensorAndConfigKey(Class<ConfigType> configType, Class<SensorType> sensorType, String name, String description, Object defaultValue) {
+        this(TypeToken.of(configType), TypeToken.of(sensorType), name, description, defaultValue);
+    }
+
+    public AttributeSensorAndConfigKey(TypeToken<ConfigType> configType, TypeToken<SensorType> sensorType, String name) {
+        this(configType, sensorType, name, null);
+    }
+
+    public AttributeSensorAndConfigKey(TypeToken<ConfigType> configType, TypeToken<SensorType> sensorType, String name, String description) {
+        this(configType, sensorType, name, description, null);
+    }
+
+    public AttributeSensorAndConfigKey(TypeToken<ConfigType> configType, TypeToken<SensorType> sensorType, String name, String description, Object defaultValue) {
+        super(sensorType, name, description);
+        ConfigType defaultValueTyped;
+        try {
+            defaultValueTyped = TypeCoercions.coerce(defaultValue, configType);
+        } catch (Exception e) {
+            log.warn("Invalid default value '"+defaultValue+"' for "+name+" (rethrowing: "+e, e);
+            throw Exceptions.propagate(e);
+        }
+        configKey = new BasicConfigKey<ConfigType>(configType, name, description, defaultValueTyped);
+    }
+
+    public AttributeSensorAndConfigKey(AttributeSensorAndConfigKey<ConfigType,SensorType> orig, ConfigType defaultValue) {
+        super(orig.getTypeToken(), orig.getName(), orig.getDescription());
+        configKey = ConfigKeys.newConfigKeyWithDefault(orig.configKey, 
+                TypeCoercions.coerce(defaultValue, orig.configKey.getTypeToken()));
+    }
+
+    public ConfigKey<ConfigType> getConfigKey() { return configKey; }
+    
+    /** returns the sensor value for this attribute on the given entity, if present,
+     * otherwise works out what the sensor value should be based on the config key's value
+     * <p>
+     * calls to this may allocate resources (e.g. ports) so should be called only once and 
+     * then (if non-null) assigned as the sensor's value
+     * <p>
+     * <b>(for this reason this method should generally not be invoked by callers except in tests and by the framework,
+     * and similarly should not be overridden; implement {@link #convertConfigToSensor(Object, Entity)} instead for single-execution calls.
+     * the framework calls this from {@link AbstractEntity#setAttribute(AttributeSensorAndConfigKey)} 
+     * typically via {@link ConfigToAttributes#apply(EntityLocal)} e.g. from SoftwareProcessImpl.preStart().)
+     * </b> 
+     */
+    public SensorType getAsSensorValue(Entity e) {
+        SensorType sensorValue = e.getAttribute(this);
+        if (sensorValue!=null) return sensorValue;
+        
+        ConfigType v = ((EntityLocal)e).getConfig(this);
+        try {
+            return convertConfigToSensor(v, e);
+        } catch (Throwable t) {
+            throw new IllegalArgumentException("Cannot convert config value "+v+" for sensor "+this+": "+t, t);
+        }
+    }
+
+    /**
+     * @see {@link #getAsSensorValue(Entity)}
+     * 
+     * Differs in that the config value is converted based on just the management context, rather
+     * than for a specific entity. For example, useful if using {@link BrooklynConfigKeys} in BrooklynWebServer.
+     * </b> 
+     */
+    public SensorType getAsSensorValue(ManagementContext managementContext) {
+        ConfigType v = managementContext.getConfig().getConfig(this);
+        try {
+            return convertConfigToSensor(v, managementContext);
+        } catch (Throwable t) {
+            throw new IllegalArgumentException("Cannot convert config value "+v+" for sensor "+this+": "+t, t);
+        }
+    }
+
+    /** converts the given ConfigType value to the corresponding SensorType value, 
+     * with respect to the given entity
+     * <p>
+     * this is invoked after checks whether the entity already has a value for the sensor,
+     * and the entity-specific config value is passed for convenience if set, 
+     * otherwise the config key default value is passed for convenience
+     * <p>
+     * this message should be allowed to return null if the conversion cannot be completed at this time */
+    protected abstract SensorType convertConfigToSensor(ConfigType value, Entity entity);
+
+    /**
+     * @see {@link #convertConfigToSensor(Object, Entity)}
+     */
+    protected abstract SensorType convertConfigToSensor(ConfigType value, ManagementContext entity);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/sensor/BasicAttributeSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/BasicAttributeSensor.java b/core/src/main/java/org/apache/brooklyn/core/sensor/BasicAttributeSensor.java
new file mode 100644
index 0000000..978e4a4
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/sensor/BasicAttributeSensor.java
@@ -0,0 +1,62 @@
+/*
+ * 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.core.sensor;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.Sensor;
+
+import com.google.common.reflect.TypeToken;
+
+/**
+ * A {@link Sensor} describing an attribute change.
+ */
+public class BasicAttributeSensor<T> extends BasicSensor<T> implements AttributeSensor<T> {
+    private static final long serialVersionUID = -2493209215974820300L;
+    
+    private final SensorPersistenceMode persistence;
+
+    public BasicAttributeSensor(Class<T> type, String name) {
+        this(type, name, name);
+    }
+    
+    public BasicAttributeSensor(Class<T> type, String name, String description) {
+        this(TypeToken.of(type), name, description);
+    }
+    
+    public BasicAttributeSensor(TypeToken<T> typeToken, String name) {
+        this(typeToken, name, name);
+    }
+    
+    public BasicAttributeSensor(TypeToken<T> typeToken, String name, String description) {
+        this(typeToken, name, description, SensorPersistenceMode.REQUIRED);
+    }
+    
+    public BasicAttributeSensor(TypeToken<T> typeToken, String name, String description, SensorPersistenceMode persistence) {
+        super(typeToken, name, description);
+        this.persistence = checkNotNull(persistence, "persistence");
+    }
+
+    @Override
+    public SensorPersistenceMode getPersistenceMode() {
+        // persistence could be null if deserializing state written by an old version; in which case default to 'required'
+        return (persistence != null) ? persistence : SensorPersistenceMode.REQUIRED;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/sensor/BasicAttributeSensorAndConfigKey.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/BasicAttributeSensorAndConfigKey.java b/core/src/main/java/org/apache/brooklyn/core/sensor/BasicAttributeSensorAndConfigKey.java
new file mode 100644
index 0000000..7c86112
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/sensor/BasicAttributeSensorAndConfigKey.java
@@ -0,0 +1,114 @@
+/*
+ * 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.core.sensor;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.config.ConfigKey;
+
+import com.google.common.reflect.TypeToken;
+
+/**
+ * A {@link Sensor} describing an attribute that can be configured with a default value.
+ *
+ * The {@link ConfigKey} has the same type, name and description as the sensor,
+ * and is typically used to populate the sensor's value at runtime.
+ */
+public class BasicAttributeSensorAndConfigKey<T> extends AttributeSensorAndConfigKey<T,T> {
+    
+    private static final long serialVersionUID = -2204916730008559688L;
+
+    public BasicAttributeSensorAndConfigKey(Class<T> type, String name) {
+        this(type, name, name, null);
+    }
+    public BasicAttributeSensorAndConfigKey(Class<T> type, String name, String description) {
+        this(type, name, description, null);
+    }
+    public BasicAttributeSensorAndConfigKey(Class<T> type, String name, String description, T defaultValue) {
+        super(type, type, name, description, defaultValue);
+    }
+
+    public BasicAttributeSensorAndConfigKey(TypeToken<T> type, String name) {
+        super(type, type, name);
+    }
+
+    public BasicAttributeSensorAndConfigKey(TypeToken<T> type, String name, String description) {
+        super(type, type, name, description);
+    }
+
+    public BasicAttributeSensorAndConfigKey(TypeToken<T> type, String name, String description, Object defaultValue) {
+        super(type, type, name, description, defaultValue);
+    }
+
+    public BasicAttributeSensorAndConfigKey(AttributeSensorAndConfigKey<T,T> orig, T defaultValue) {
+        super(orig, defaultValue);
+    }
+    
+    @Override
+    protected T convertConfigToSensor(T value, Entity entity) { return value; }
+
+    @Override
+    protected T convertConfigToSensor(T value, ManagementContext managementContext) { return value; }
+    
+    public static class StringAttributeSensorAndConfigKey extends BasicAttributeSensorAndConfigKey<String> {
+
+        private static final long serialVersionUID = 810512615528081865L;
+
+        public StringAttributeSensorAndConfigKey(AttributeSensorAndConfigKey<String,String> orig, String defaultValue) {
+            super(orig, defaultValue);
+        }
+
+        public StringAttributeSensorAndConfigKey(String name, String description, String defaultValue) {
+            super(String.class, name, description, defaultValue);
+        }
+
+        public StringAttributeSensorAndConfigKey(String name, String description) {
+            super(String.class, name, description);
+        }
+
+        public StringAttributeSensorAndConfigKey(String name) {
+            super(String.class, name);
+        }
+        
+    }
+    
+    public static class IntegerAttributeSensorAndConfigKey extends BasicAttributeSensorAndConfigKey<Integer> {
+
+        private static final long serialVersionUID = 7159564523829723929L;
+
+        public IntegerAttributeSensorAndConfigKey(AttributeSensorAndConfigKey<Integer,Integer> orig, Integer defaultValue) {
+            super(orig, defaultValue);
+        }
+
+        public IntegerAttributeSensorAndConfigKey(String name, String description, Integer defaultValue) {
+            super(Integer.class, name, description, defaultValue);
+        }
+
+        public IntegerAttributeSensorAndConfigKey(String name, String description) {
+            super(Integer.class, name, description);
+        }
+
+        public IntegerAttributeSensorAndConfigKey(String name) {
+            super(Integer.class, name);
+        }
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/sensor/BasicNotificationSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/BasicNotificationSensor.java b/core/src/main/java/org/apache/brooklyn/core/sensor/BasicNotificationSensor.java
new file mode 100644
index 0000000..d3a11cf
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/sensor/BasicNotificationSensor.java
@@ -0,0 +1,36 @@
+/*
+ * 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.core.sensor;
+
+import org.apache.brooklyn.api.sensor.Sensor;
+
+/**
+ * A {@link Sensor} used to notify subscribers about events.
+ */
+public class BasicNotificationSensor<T> extends BasicSensor<T> {
+    private static final long serialVersionUID = -7670909215973264600L;
+
+    public BasicNotificationSensor(Class<T> type, String name) {
+        this(type, name, name);
+    }
+    
+    public BasicNotificationSensor(Class<T> type, String name, String description) {
+        super(type, name, description);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/sensor/BasicSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/BasicSensor.java b/core/src/main/java/org/apache/brooklyn/core/sensor/BasicSensor.java
new file mode 100644
index 0000000..efb610f
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/sensor/BasicSensor.java
@@ -0,0 +1,114 @@
+/*
+ * 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.core.sensor;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.api.sensor.SensorEvent;
+import org.apache.brooklyn.util.guava.TypeTokens;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableList;
+import com.google.common.reflect.TypeToken;
+
+/**
+ * Parent for all {@link Sensor}s.
+ */
+public class BasicSensor<T> implements Sensor<T> {
+    private static final long serialVersionUID = -3762018534086101323L;
+    
+    private static final Splitter dots = Splitter.on('.');
+
+    private TypeToken<T> typeToken;
+    private Class<? super T> type;
+    private String name;
+    private String description;
+    private transient List<String> nameParts;
+    
+    // FIXME In groovy, fields were `public final` with a default constructor; do we need the gson?
+    public BasicSensor() { /* for gson */ }
+
+    /** name is typically a dot-separated identifier; description is optional */
+    public BasicSensor(Class<T> type, String name) {
+        this(type, name, name);
+    }
+    
+    public BasicSensor(Class<T> type, String name, String description) {
+        this(TypeToken.of(type), name, description);
+    }
+    
+    public BasicSensor(TypeToken<T> typeToken, String name, String description) {
+        this.typeToken = TypeTokens.getTypeTokenIfNotRaw(checkNotNull(typeToken, "typeToken"));
+        this.type = TypeTokens.getRawTypeIfRaw(typeToken);
+        this.name = checkNotNull(name, "name");
+        this.description = description;
+    }
+
+    /** @see Sensor#getTypeToken() */
+    public TypeToken<T> getTypeToken() { return TypeTokens.getTypeToken(typeToken, type); }
+    
+    /** @see Sensor#getType() */
+    public Class<? super T> getType() { return TypeTokens.getRawType(typeToken, type); }
+ 
+    /** @see Sensor#getTypeName() */
+    public String getTypeName() { 
+        return getType().getName();
+    }
+ 
+    /** @see Sensor#getName() */
+    public String getName() { return name; }
+ 
+    /** @see Sensor#getNameParts() */
+    public synchronized List<String> getNameParts() {
+        if (nameParts==null) nameParts = ImmutableList.copyOf(dots.split(name));
+        return nameParts; 
+    }
+ 
+    /** @see Sensor#getDescription() */
+    public String getDescription() { return description; }
+    
+    /** @see Sensor#newEvent(Entity, Object) */
+    public SensorEvent<T> newEvent(Entity producer, T value) {
+        return new BasicSensorEvent<T>(this, producer, value);
+    }
+    
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(getTypeName(), name, description);
+    }
+ 
+    @Override
+    public boolean equals(Object other) {
+        if (this==other) return true;
+        if (!(other instanceof BasicSensor)) return false;
+        BasicSensor<?> o = (BasicSensor<?>) other;
+        
+        return Objects.equal(getTypeName(), o.getTypeName()) && Objects.equal(name, o.name) && Objects.equal(description, o.description);
+    }
+    
+    @Override
+    public String toString() {
+        return String.format("Sensor: %s (%s)", name, getTypeName());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/core/sensor/BasicSensorEvent.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/BasicSensorEvent.java b/core/src/main/java/org/apache/brooklyn/core/sensor/BasicSensorEvent.java
new file mode 100644
index 0000000..44453fc
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/sensor/BasicSensorEvent.java
@@ -0,0 +1,112 @@
+/*
+ * 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.core.sensor;
+
+import java.util.ConcurrentModificationException;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.api.sensor.SensorEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Objects;
+
+/**
+ * A {@link SensorEvent} containing data from a {@link Sensor} generated by an {@link Entity}.
+ */
+public class BasicSensorEvent<T> implements SensorEvent<T> {
+    
+    private static final Logger log = LoggerFactory.getLogger(BasicSensorEvent.class);
+    
+    private final Sensor<T> sensor;
+    private final Entity source;
+    private final T value;
+    private final long timestamp;
+    
+    public T getValue() { return value; }
+
+    public Sensor<T> getSensor() { return sensor; }
+
+    public Entity getSource() { return source; }
+
+    public long getTimestamp() { return timestamp; }
+
+    /** arguments should not be null (except in certain limited testing situations) */
+    public BasicSensorEvent(Sensor<T> sensor, Entity source, T value) {
+        this(sensor, source, value, System.currentTimeMillis());
+    }
+    
+    public BasicSensorEvent(Sensor<T> sensor, Entity source, T value, long timestamp) {
+        this.sensor = sensor;
+        this.source = source;
+        this.value = value;
+        this.timestamp = timestamp;
+    }
+    
+    public static <T> SensorEvent<T> of(Sensor<T> sensor, Entity source, T value, long timestamp) {
+        return new BasicSensorEvent<T>(sensor, source, value, timestamp);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> SensorEvent<T> ofUnchecked(Sensor<T> sensor, Entity source, Object value, long timestamp) {
+        return new BasicSensorEvent<T>(sensor, source, (T)value, timestamp);
+    }
+
+    public static <T> SensorEvent<T> of(Sensor<T> sensor, Entity source, T value) {
+        return new BasicSensorEvent<T>(sensor, source, value);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> SensorEvent<T> ofUnchecked(Sensor<T> sensor, Entity source, Object value) {
+        return new BasicSensorEvent<T>(sensor, source, (T)value);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(sensor, source, value);
+    }   
+
+    /**
+     * Any SensorEvents are equal if their sensor, source and value are equal.
+     * Ignore timestamp for ease of use in unit tests.   
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof SensorEvent)) return false;
+        SensorEvent<?> other = (SensorEvent<?>) o;
+        return Objects.equal(sensor, other.getSensor()) && Objects.equal(source, other.getSource()) &&
+                Objects.equal(value, other.getValue());
+    }
+    
+    @Override
+    public String toString() {
+        try {
+            return source+"."+sensor+"="+value+" @ "+timestamp;
+        } catch (ConcurrentModificationException e) {
+            // TODO occasional CME observed on shutdown, wrt map, e.g. in UrlMappingTest
+            // transformations should set a copy of the map; see e.g. in ServiceStateLogic.updateMapSensor
+            String result = getClass()+":"+source+"."+sensor+"@"+timestamp;
+            log.warn("Error creating string for " + result + " (ignoring): " + e);
+            if (log.isDebugEnabled())
+                log.debug("Trace for error creating string for " + result + " (ignoring): " + e, e);
+            return result;
+        }
+    }
+}


[35/36] incubator-brooklyn git commit: Rename o.a.b.sensor.enricher to o.a.b.core.enricher

Posted by he...@apache.org.
Rename o.a.b.sensor.enricher to o.a.b.core.enricher 

- and o.a.b.enricher.stock for actual enricher impls

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

Branch: refs/heads/master
Commit: 6f15e8a6d61c2e648547cf7faba03fbc06716421
Parents: daf4091
Author: Aled Sage <al...@gmail.com>
Authored: Wed Aug 19 23:07:28 2015 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Wed Aug 19 23:07:28 2015 +0100

----------------------------------------------------------------------
 .../core/enricher/AbstractEnricher.java         | 115 +++
 .../core/enricher/EnricherDynamicType.java      |  43 +
 .../core/enricher/EnricherTypeSnapshot.java     |  39 +
 .../brooklyn/core/entity/AbstractEntity.java    |   2 +-
 .../entity/lifecycle/ServiceStateLogic.java     |   8 +-
 .../mgmt/rebind/BasicEnricherRebindSupport.java |   2 +-
 .../mgmt/rebind/BasicEntityRebindSupport.java   |   2 +-
 .../core/mgmt/rebind/RebindIteration.java       |   2 +-
 .../core/mgmt/rebind/RebindManagerImpl.java     |   2 +-
 .../mgmt/rebind/dto/MementosGenerators.java     |   2 +-
 .../core/objs/AbstractEntityAdjunct.java        |   2 +-
 .../brooklyn/core/objs/BrooklynTypes.java       |   2 +-
 .../core/objs/proxy/InternalPolicyFactory.java  |   2 +-
 .../brooklyn/core/sensor/StaticSensor.java      |   2 +-
 .../stock/AbstractAggregatingEnricher.java      | 174 ++++
 .../enricher/stock/AbstractAggregator.java      | 238 ++++++
 .../stock/AbstractMultipleSensorAggregator.java | 169 ++++
 .../enricher/stock/AbstractTransformer.java     | 101 +++
 .../stock/AbstractTransformingEnricher.java     |  38 +
 .../stock/AbstractTypeTransformingEnricher.java |  68 ++
 .../brooklyn/enricher/stock/AddingEnricher.java | 107 +++
 .../brooklyn/enricher/stock/Aggregator.java     | 222 +++++
 .../brooklyn/enricher/stock/Combiner.java       | 138 ++++
 .../stock/CustomAggregatingEnricher.java        | 320 +++++++
 .../brooklyn/enricher/stock/Enrichers.java      | 825 +++++++++++++++++++
 .../apache/brooklyn/enricher/stock/Joiner.java  | 127 +++
 .../brooklyn/enricher/stock/Propagator.java     | 201 +++++
 .../stock/SensorPropagatingEnricher.java        | 181 ++++
 .../stock/SensorTransformingEnricher.java       | 106 +++
 .../brooklyn/enricher/stock/Transformer.java    | 103 +++
 .../brooklyn/enricher/stock/UpdatingMap.java    | 159 ++++
 .../YamlRollingTimeWindowMeanEnricher.java      | 178 ++++
 .../stock/YamlTimeWeightedDeltaEnricher.java    |  83 ++
 .../entity/group/DynamicFabricImpl.java         |   2 +-
 .../entity/stock/DelegateEntityImpl.java        |   2 +-
 .../enricher/AbstractAggregatingEnricher.java   | 173 ----
 .../sensor/enricher/AbstractAggregator.java     | 237 ------
 .../sensor/enricher/AbstractEnricher.java       | 115 ---
 .../AbstractMultipleSensorAggregator.java       | 169 ----
 .../sensor/enricher/AbstractTransformer.java    | 100 ---
 .../enricher/AbstractTransformingEnricher.java  |  38 -
 .../AbstractTypeTransformingEnricher.java       |  67 --
 .../sensor/enricher/AddingEnricher.java         | 106 ---
 .../brooklyn/sensor/enricher/Aggregator.java    | 221 -----
 .../brooklyn/sensor/enricher/Combiner.java      | 137 ---
 .../enricher/CustomAggregatingEnricher.java     | 320 -------
 .../sensor/enricher/EnricherDynamicType.java    |  43 -
 .../sensor/enricher/EnricherTypeSnapshot.java   |  39 -
 .../brooklyn/sensor/enricher/Enrichers.java     | 824 ------------------
 .../apache/brooklyn/sensor/enricher/Joiner.java | 126 ---
 .../brooklyn/sensor/enricher/Propagator.java    | 200 -----
 .../enricher/SensorPropagatingEnricher.java     | 180 ----
 .../enricher/SensorTransformingEnricher.java    | 106 ---
 .../brooklyn/sensor/enricher/Transformer.java   | 103 ---
 .../brooklyn/sensor/enricher/UpdatingMap.java   | 158 ----
 .../YamlRollingTimeWindowMeanEnricher.java      | 178 ----
 .../enricher/YamlTimeWeightedDeltaEnricher.java |  83 --
 .../core/enricher/BasicEnricherTest.java        | 119 +++
 .../core/enricher/EnricherConfigTest.java       | 147 ++++
 .../brooklyn/core/entity/EntitySpecTest.java    |   2 +-
 .../BrooklynMementoPersisterTestFixture.java    |   2 +-
 .../core/mgmt/rebind/RebindEnricherTest.java    |   4 +-
 .../core/mgmt/rebind/RebindFailuresTest.java    |   2 +-
 .../core/mgmt/rebind/RebindPolicyTest.java      |   2 +-
 .../core/policy/basic/EnricherTypeTest.java     |   2 +-
 .../brooklyn/core/test/policy/TestEnricher.java |   2 +-
 ...stomAggregatingEnricherDeprecatedTest.groovy | 368 +++++++++
 .../stock/CustomAggregatingEnricherTest.java    | 556 +++++++++++++
 .../brooklyn/enricher/stock/EnrichersTest.java  | 501 +++++++++++
 ...SensorPropagatingEnricherDeprecatedTest.java | 108 +++
 .../stock/SensorPropagatingEnricherTest.java    | 218 +++++
 .../TransformingEnricherDeprecatedTest.groovy   |  83 ++
 .../stock/TransformingEnricherTest.java         |  71 ++
 .../YamlRollingTimeWindowMeanEnricherTest.java  | 179 ++++
 .../YamlTimeWeightedDeltaEnricherTest.java      | 107 +++
 .../sensor/enricher/BasicEnricherTest.java      | 119 ---
 ...stomAggregatingEnricherDeprecatedTest.groovy | 367 ---------
 .../enricher/CustomAggregatingEnricherTest.java | 556 -------------
 .../sensor/enricher/EnricherConfigTest.java     | 147 ----
 .../brooklyn/sensor/enricher/EnrichersTest.java | 501 -----------
 ...SensorPropagatingEnricherDeprecatedTest.java | 108 ---
 .../enricher/SensorPropagatingEnricherTest.java | 218 -----
 .../TransformingEnricherDeprecatedTest.groovy   |  82 --
 .../enricher/TransformingEnricherTest.java      |  71 --
 .../YamlRollingTimeWindowMeanEnricherTest.java  | 179 ----
 .../YamlTimeWeightedDeltaEnricherTest.java      | 107 ---
 .../brooklyn/demo/ResilientMongoDbApp.java      |   2 +-
 .../demo/WebClusterDatabaseExample.java         |   2 +-
 .../demo/WebClusterDatabaseExampleApp.java      |   2 +-
 ...lusterDatabaseExampleAppIntegrationTest.java |   2 +-
 .../brooklyn/policy/enricher/DeltaEnricher.java |   2 +-
 .../policy/enricher/HttpLatencyDetector.java    |   2 +-
 .../policy/enricher/RollingMeanEnricher.java    |   2 +-
 .../enricher/RollingTimeWindowMeanEnricher.java |   4 +-
 .../enricher/TimeFractionDeltaEnricher.java     |   2 +-
 .../enricher/TimeWeightedDeltaEnricher.java     |   4 +-
 .../brooklynnode/BrooklynClusterImpl.java       |   2 +-
 .../entity/brooklynnode/BrooklynNodeImpl.java   |   2 +-
 .../software/base/SoftwareProcessImpl.java      |   2 +-
 .../system_service/SystemServiceEnricher.java   |   2 +-
 .../entity/database/crate/CrateNodeImpl.java    |   2 +-
 .../entity/database/mysql/MySqlClusterImpl.java |   2 +-
 .../messaging/kafka/KafkaClusterImpl.java       |   2 +-
 .../messaging/storm/StormDeploymentImpl.java    |   2 +-
 .../bind/BindDnsServerIntegrationTest.java      |   2 +-
 .../network/bind/PrefixAndIdEnricher.java       |   2 +-
 .../cassandra/CassandraDatacenterImpl.java      |   2 +-
 .../nosql/couchbase/CouchbaseClusterImpl.java   |   2 +-
 .../nosql/mongodb/MongoDBReplicaSetImpl.java    |   2 +-
 .../sharding/CoLocatedMongoDBRouterImpl.java    |   2 +-
 .../sharding/MongoDBShardedDeploymentImpl.java  |   2 +-
 .../entity/nosql/redis/RedisClusterImpl.java    |   2 +-
 .../entity/nosql/riak/RiakClusterImpl.java      |   2 +-
 .../entity/nosql/riak/RiakNodeImpl.java         |   2 +-
 .../entity/proxy/nginx/NginxControllerImpl.java |   2 +-
 .../ControlledDynamicWebAppClusterImpl.java     |   2 +-
 .../entity/webapp/DynamicWebAppClusterImpl.java |   2 +-
 .../entity/webapp/DynamicWebAppFabricImpl.java  |   2 +-
 .../entity/webapp/jboss/JBoss6ServerImpl.java   |   2 +-
 .../entity/webapp/jboss/JBoss7ServerImpl.java   |   2 +-
 .../entity/webapp/jetty/Jetty6ServerImpl.java   |   2 +-
 .../app/ClusterWebServerDatabaseSample.java     |   4 +-
 .../camp/brooklyn/EnrichersYamlTest.java        |   2 +-
 .../camp/brooklyn/TestReferencingEnricher.java  |   2 +-
 ...est-app-with-enrichers-slightly-simpler.yaml |  12 +-
 .../test-webapp-with-averaging-enricher.yaml    |   4 +-
 .../apache/brooklyn/cli/lister/ClassFinder.java |   2 +-
 .../qa/load/SimulatedJBoss7ServerImpl.java      |   2 +-
 .../brooklyn/qa/load/SimulatedTheeTierApp.java  |   2 +-
 .../webcluster/SinusoidalLoadGenerator.java     |   2 +-
 .../qa/longevity/webcluster/WebClusterApp.java  |   2 +-
 .../rest/util/BrooklynRestResourceUtils.java    |   2 +-
 132 files changed, 6271 insertions(+), 6257 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/core/enricher/AbstractEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/enricher/AbstractEnricher.java b/core/src/main/java/org/apache/brooklyn/core/enricher/AbstractEnricher.java
new file mode 100644
index 0000000..0dc36f6
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/enricher/AbstractEnricher.java
@@ -0,0 +1,115 @@
+/*
+ * 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.core.enricher;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.mgmt.rebind.RebindSupport;
+import org.apache.brooklyn.api.mgmt.rebind.mementos.EnricherMemento;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.Enricher;
+import org.apache.brooklyn.api.sensor.EnricherType;
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.mgmt.rebind.BasicEnricherRebindSupport;
+import org.apache.brooklyn.core.objs.AbstractEntityAdjunct;
+import org.apache.brooklyn.util.core.flags.TypeCoercions;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.Maps;
+
+/**
+* Base {@link Enricher} implementation; all enrichers should extend this or its children
+*/
+public abstract class AbstractEnricher extends AbstractEntityAdjunct implements Enricher {
+
+    public static final ConfigKey<Boolean> SUPPRESS_DUPLICATES = ConfigKeys.newBooleanConfigKey("enricher.suppressDuplicates",
+        "Whether duplicate values published by this enricher should be suppressed");
+
+    private final EnricherDynamicType enricherType;
+    protected Boolean suppressDuplicates;
+
+    public AbstractEnricher() {
+        this(Maps.newLinkedHashMap());
+    }
+    
+    public AbstractEnricher(Map<?,?> flags) {
+        super(flags);
+        
+        enricherType = new EnricherDynamicType(this);
+        
+        if (isLegacyConstruction() && !isLegacyNoConstructionInit()) {
+            init();
+        }
+    }
+
+    @Override
+    public RebindSupport<EnricherMemento> getRebindSupport() {
+        return new BasicEnricherRebindSupport(this);
+    }
+    
+    @Override
+    public EnricherType getEnricherType() {
+        return enricherType.getSnapshot();
+    }
+
+    @Override
+    public void setEntity(EntityLocal entity) {
+        super.setEntity(entity);
+        Boolean suppressDuplicates = getConfig(SUPPRESS_DUPLICATES);
+        if (suppressDuplicates!=null) 
+            this.suppressDuplicates = suppressDuplicates;
+    }
+    
+    @Override
+    protected void onChanged() {
+        requestPersist();
+    }
+
+    @Override
+    protected <T> void emit(Sensor<T> sensor, Object val) {
+        checkState(entity != null, "entity must first be set");
+        if (val == Entities.UNCHANGED) {
+            return;
+        }
+        if (val == Entities.REMOVE) {
+            ((EntityInternal)entity).removeAttribute((AttributeSensor<T>) sensor);
+            return;
+        }
+        
+        T newVal = TypeCoercions.coerce(val, sensor.getTypeToken());
+        if (sensor instanceof AttributeSensor) {
+            if (Boolean.TRUE.equals(suppressDuplicates)) {
+                T oldValue = entity.getAttribute((AttributeSensor<T>)sensor);
+                if (Objects.equal(oldValue, newVal))
+                    return;
+            }
+            entity.setAttribute((AttributeSensor<T>)sensor, newVal);
+        } else { 
+            entity.emit(sensor, newVal);
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/core/enricher/EnricherDynamicType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/enricher/EnricherDynamicType.java b/core/src/main/java/org/apache/brooklyn/core/enricher/EnricherDynamicType.java
new file mode 100644
index 0000000..b6a0b23
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/enricher/EnricherDynamicType.java
@@ -0,0 +1,43 @@
+/*
+ * 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.core.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/core/enricher/EnricherTypeSnapshot.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/enricher/EnricherTypeSnapshot.java b/core/src/main/java/org/apache/brooklyn/core/enricher/EnricherTypeSnapshot.java
new file mode 100644
index 0000000..240d884
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/enricher/EnricherTypeSnapshot.java
@@ -0,0 +1,39 @@
+/*
+ * 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.core.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/core/entity/AbstractEntity.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java b/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
index 0ec5903..fb8f2d0 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
@@ -59,6 +59,7 @@ import org.apache.brooklyn.core.BrooklynFeatureEnablement;
 import org.apache.brooklyn.core.BrooklynLogging;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.config.render.RendererHints;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
 import org.apache.brooklyn.core.entity.internal.EntityConfigMap;
 import org.apache.brooklyn.core.entity.lifecycle.PolicyDescriptor;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
@@ -83,7 +84,6 @@ import org.apache.brooklyn.core.sensor.AttributeMap;
 import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
 import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
 import org.apache.brooklyn.core.sensor.Sensors;
-import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/core/entity/lifecycle/ServiceStateLogic.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/lifecycle/ServiceStateLogic.java b/core/src/main/java/org/apache/brooklyn/core/entity/lifecycle/ServiceStateLogic.java
index 654662f..c2606c1 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/lifecycle/ServiceStateLogic.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/lifecycle/ServiceStateLogic.java
@@ -42,16 +42,16 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.BrooklynLogging;
 import org.apache.brooklyn.core.BrooklynLogging.LoggingLevel;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityAdjuncts;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.EntityPredicates;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle.Transition;
-import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
-import org.apache.brooklyn.sensor.enricher.AbstractMultipleSensorAggregator;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
-import org.apache.brooklyn.sensor.enricher.UpdatingMap;
+import org.apache.brooklyn.enricher.stock.AbstractMultipleSensorAggregator;
+import org.apache.brooklyn.enricher.stock.Enrichers;
+import org.apache.brooklyn.enricher.stock.UpdatingMap;
 import org.apache.brooklyn.util.collections.CollectionFunctionals;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicEnricherRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicEnricherRebindSupport.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicEnricherRebindSupport.java
index 89e11e2..3903655 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicEnricherRebindSupport.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicEnricherRebindSupport.java
@@ -20,7 +20,7 @@ package org.apache.brooklyn.core.mgmt.rebind;
 
 import org.apache.brooklyn.api.mgmt.rebind.RebindContext;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.EnricherMemento;
-import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.flags.FlagUtils;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicEntityRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicEntityRebindSupport.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicEntityRebindSupport.java
index 2a5e92e..0d80698 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicEntityRebindSupport.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicEntityRebindSupport.java
@@ -32,13 +32,13 @@ import org.apache.brooklyn.api.mgmt.rebind.mementos.EntityMemento;
 import org.apache.brooklyn.api.objs.BrooklynObjectType;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.feed.AbstractFeed;
 import org.apache.brooklyn.core.mgmt.rebind.dto.MementosGenerators;
 import org.apache.brooklyn.core.policy.AbstractPolicy;
 import org.apache.brooklyn.entity.group.AbstractGroupImpl;
-import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java
index e9478ef..3f468ba 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java
@@ -64,6 +64,7 @@ import org.apache.brooklyn.core.BrooklynLogging;
 import org.apache.brooklyn.core.BrooklynLogging.LoggingLevel;
 import org.apache.brooklyn.core.catalog.internal.CatalogInitialization;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
 import org.apache.brooklyn.core.entity.AbstractApplication;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.entity.EntityInternal;
@@ -86,7 +87,6 @@ import org.apache.brooklyn.core.objs.proxy.InternalFactory;
 import org.apache.brooklyn.core.objs.proxy.InternalLocationFactory;
 import org.apache.brooklyn.core.objs.proxy.InternalPolicyFactory;
 import org.apache.brooklyn.core.policy.AbstractPolicy;
-import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.flags.FlagUtils;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindManagerImpl.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindManagerImpl.java
index fdce617..52b984a 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindManagerImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindManagerImpl.java
@@ -46,6 +46,7 @@ import org.apache.brooklyn.api.objs.BrooklynObject;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.BrooklynFeatureEnablement;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.mgmt.ha.HighAvailabilityManagerImpl;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
@@ -55,7 +56,6 @@ import org.apache.brooklyn.core.mgmt.persist.PersistenceActivityMetrics;
 import org.apache.brooklyn.core.mgmt.persist.BrooklynPersistenceUtils.CreateBackupMode;
 import org.apache.brooklyn.core.mgmt.rebind.transformer.CompoundTransformer;
 import org.apache.brooklyn.core.server.BrooklynServerConfig;
-import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.QuorumCheck;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
index 929b63c..36daf49 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
@@ -49,6 +49,7 @@ import org.apache.brooklyn.api.sensor.Feed;
 import org.apache.brooklyn.api.sensor.AttributeSensor.SensorPersistenceMode;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.catalog.internal.CatalogItemDo;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
 import org.apache.brooklyn.core.entity.EntityDynamicType;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.feed.AbstractFeed;
@@ -58,7 +59,6 @@ import org.apache.brooklyn.core.mgmt.rebind.AbstractBrooklynObjectRebindSupport;
 import org.apache.brooklyn.core.mgmt.rebind.TreeUtils;
 import org.apache.brooklyn.core.objs.BrooklynTypes;
 import org.apache.brooklyn.core.policy.AbstractPolicy;
-import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.flags.FlagUtils;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java
index efd89d1..e85cc73 100644
--- a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java
+++ b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java
@@ -44,10 +44,10 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.config.ConfigMap;
 import org.apache.brooklyn.config.ConfigKey.HasConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.mgmt.internal.SubscriptionTracker;
-import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.flags.FlagUtils;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynTypes.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynTypes.java b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynTypes.java
index b6e68ff..4170613 100644
--- a/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynTypes.java
+++ b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynTypes.java
@@ -27,9 +27,9 @@ import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.sensor.Enricher;
 import org.apache.brooklyn.api.sensor.Sensor;
 import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.enricher.EnricherDynamicType;
 import org.apache.brooklyn.core.entity.EntityDynamicType;
 import org.apache.brooklyn.core.policy.PolicyDynamicType;
-import org.apache.brooklyn.sensor.enricher.EnricherDynamicType;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 
 import com.google.common.collect.Maps;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java
index 4e45580..aaee778 100644
--- a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java
+++ b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java
@@ -27,10 +27,10 @@ import org.apache.brooklyn.api.sensor.Enricher;
 import org.apache.brooklyn.api.sensor.EnricherSpec;
 import org.apache.brooklyn.api.sensor.Feed;
 import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.policy.AbstractPolicy;
-import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.exceptions.Exceptions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/core/sensor/StaticSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/StaticSensor.java b/core/src/main/java/org/apache/brooklyn/core/sensor/StaticSensor.java
index 4a7b1d4..b017315 100644
--- a/core/src/main/java/org/apache/brooklyn/core/sensor/StaticSensor.java
+++ b/core/src/main/java/org/apache/brooklyn/core/sensor/StaticSensor.java
@@ -23,7 +23,7 @@ import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.effector.AddSensor;
-import org.apache.brooklyn.sensor.enricher.Propagator;
+import org.apache.brooklyn.enricher.stock.Propagator;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.task.Tasks;
 import org.apache.brooklyn.util.core.task.ValueResolver;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/enricher/stock/AbstractAggregatingEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/AbstractAggregatingEnricher.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/AbstractAggregatingEnricher.java
new file mode 100644
index 0000000..2d25a75
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/AbstractAggregatingEnricher.java
@@ -0,0 +1,174 @@
+/*
+ * 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.enricher.stock;
+
+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.entity.Group;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.SensorEvent;
+import org.apache.brooklyn.api.sensor.SensorEventListener;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
+import org.apache.brooklyn.core.entity.trait.Changeable;
+import org.apache.brooklyn.util.groovy.GroovyJavaMethods;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableMap;
+
+
+/**
+ * AggregatingEnrichers implicitly subscribes to the same sensor<S> on all entities inside an
+ * {@link Group} and should emit an aggregate<T> on the target sensor
+ * 
+ * @deprecated since 0.7.0; use {@link Enrichers.builder()}
+ * @see Aggregator if need to sub-class
+ */
+public abstract class AbstractAggregatingEnricher<S,T> extends AbstractEnricher implements SensorEventListener<S> {
+    
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractAggregatingEnricher.class);
+    
+    AttributeSensor<? extends S> source;
+    protected AttributeSensor<T> target;
+    protected S defaultValue;
+
+    Set<Entity> producers;
+    List<Entity> hardCodedProducers;
+    boolean allMembers;
+    Predicate<Entity> filter;
+    
+    /**
+     * 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<Entity, S> values = Collections.synchronizedMap(new LinkedHashMap<Entity, S>());
+
+    public AbstractAggregatingEnricher(Map<String,?> flags, AttributeSensor<? extends S> source, AttributeSensor<T> target) {
+        this(flags, source, target, null);
+    }
+    
+    @SuppressWarnings("unchecked")
+    public AbstractAggregatingEnricher(Map<String,?> flags, AttributeSensor<? extends S> source, AttributeSensor<T> target, S defaultValue) {
+        super(flags);
+        this.source = source;
+        this.target = target;
+        this.defaultValue = defaultValue;
+        hardCodedProducers = (List<Entity>) (flags.containsKey("producers") ? flags.get("producers") : Collections.emptyList());
+        allMembers = (Boolean) (flags.containsKey("allMembers") ? flags.get("allMembers") : false);
+        filter = flags.containsKey("filter") ? GroovyJavaMethods.<Entity>castToPredicate(flags.get("filter")) : Predicates.<Entity>alwaysTrue();
+    }
+
+    public void addProducer(Entity producer) {
+        if (LOG.isDebugEnabled()) LOG.debug("{} linked ({}, {}) to {}", new Object[] {this, producer, source, target});
+        subscribe(producer, source, this);
+        synchronized (values) {
+            S vo = values.get(producer);
+            if (vo==null) {
+                S initialVal = ((EntityLocal)producer).getAttribute(source);
+                values.put(producer, initialVal != null ? initialVal : defaultValue);
+                //we might skip in onEvent in the short window while !values.containsKey(producer)
+                //but that's okay because the put which would have been done there is done here now
+            } else {
+                //vo will be null unless some weird race with addProducer+removeProducer is occuring
+                //(and that's something we can tolerate i think)
+                if (LOG.isDebugEnabled()) LOG.debug("{} already had value ({}) for producer ({}); but that producer has just been added", new Object[] {this, vo, producer});
+            }
+        }
+        onUpdated();
+    }
+    
+    // TODO If producer removed but then get (queued) event from it after this method returns,  
+    public S removeProducer(Entity producer) {
+        if (LOG.isDebugEnabled()) LOG.debug("{} unlinked ({}, {}) from {}", new Object[] {this, producer, source, target});
+        unsubscribe(producer);
+        S removed = values.remove(producer);
+        onUpdated();
+        return removed;
+    }
+    
+    @Override
+    public void onEvent(SensorEvent<S> event) {
+        Entity e = event.getSource();
+        synchronized (values) {
+            if (values.containsKey(e)) {
+                values.put(e, event.getValue());
+            } else {
+                if (LOG.isDebugEnabled()) LOG.debug("{} received event for unknown producer ({}); presumably that producer has recently been removed", this, e);
+            }
+        }
+        onUpdated();
+    }
+
+    /**
+     * Called whenever the values for the set of producers changes (e.g. on an event, or on a member added/removed).
+     * Defaults to no-op
+     */
+    // TODO should this be abstract?
+    protected void onUpdated() {
+        // no-op
+    }
+    
+    @Override
+    public void setEntity(EntityLocal entity) {
+        super.setEntity(entity);
+        
+        for (Entity producer : hardCodedProducers) {
+            if (filter.apply(producer)) {
+                addProducer(producer);
+            }
+        }
+        
+        if (allMembers) {
+            subscribe(entity, Changeable.MEMBER_ADDED, new SensorEventListener<Entity>() {
+                @Override public void onEvent(SensorEvent<Entity> it) {
+                    if (filter.apply(it.getValue())) addProducer(it.getValue());
+                }
+            });
+            subscribe(entity, Changeable.MEMBER_REMOVED, new SensorEventListener<Entity>() {
+                @Override public void onEvent(SensorEvent<Entity> it) {
+                    removeProducer(it.getValue());
+                }
+            });
+            
+            if (entity instanceof Group) {
+                for (Entity member : ((Group)entity).getMembers()) {
+                    if (filter.apply(member)) {
+                        addProducer(member);
+                    }
+                }
+            }
+        }
+    }
+    
+    protected Map<Entity, S> copyOfValues() {
+        synchronized (values) {
+            return ImmutableMap.copyOf(values);
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/enricher/stock/AbstractAggregator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/AbstractAggregator.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/AbstractAggregator.java
new file mode 100644
index 0000000..926b769
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/AbstractAggregator.java
@@ -0,0 +1,238 @@
+/*
+ * 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.enricher.stock;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.entity.Group;
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.api.sensor.SensorEvent;
+import org.apache.brooklyn.api.sensor.SensorEventListener;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
+import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.core.entity.trait.Changeable;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.reflect.TypeToken;
+
+/** Abstract superclass for enrichers which aggregate from children and/or members */
+@SuppressWarnings("serial")
+public abstract class AbstractAggregator<T,U> extends AbstractEnricher implements SensorEventListener<T> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractAggregator.class);
+
+    public static final ConfigKey<Entity> PRODUCER = ConfigKeys.newConfigKey(Entity.class, "enricher.producer", "The entity whose children/members will be aggregated");
+
+    public static final ConfigKey<Sensor<?>> TARGET_SENSOR = ConfigKeys.newConfigKey(new TypeToken<Sensor<?>>() {}, "enricher.targetSensor");
+
+    // FIXME this is not just for "members" i think -Alex
+    public static final ConfigKey<?> DEFAULT_MEMBER_VALUE = ConfigKeys.newConfigKey(Object.class, "enricher.defaultMemberValue");
+
+    public static final ConfigKey<Set<? extends Entity>> FROM_HARDCODED_PRODUCERS = ConfigKeys.newConfigKey(new TypeToken<Set<? extends Entity>>() {}, "enricher.aggregating.fromHardcodedProducers");
+
+    public static final ConfigKey<Boolean> FROM_MEMBERS = ConfigKeys.newBooleanConfigKey("enricher.aggregating.fromMembers",
+        "Whether this enricher looks at members; only supported if a Group producer is supplier; defaults to true for Group entities");
+
+    public static final ConfigKey<Boolean> FROM_CHILDREN = ConfigKeys.newBooleanConfigKey("enricher.aggregating.fromChildren",
+        "Whether this enricher looks at children; this is the default for non-Group producers");
+
+    public static final ConfigKey<Predicate<? super Entity>> ENTITY_FILTER = ConfigKeys.newConfigKey(new TypeToken<Predicate<? super Entity>>() {}, "enricher.aggregating.entityFilter");
+
+    public static final ConfigKey<Predicate<?>> VALUE_FILTER = ConfigKeys.newConfigKey(new TypeToken<Predicate<?>>() {}, "enricher.aggregating.valueFilter");
+
+    protected Entity producer;
+    protected Sensor<U> targetSensor;
+    protected T defaultMemberValue;
+    protected Set<? extends Entity> fromHardcodedProducers;
+    protected Boolean fromMembers;
+    protected Boolean fromChildren;
+    protected Predicate<? super Entity> entityFilter;
+    protected Predicate<? super T> valueFilter;
+    
+    public AbstractAggregator() {}
+
+    @Override
+    public void setEntity(EntityLocal entity) {
+        super.setEntity(entity);
+        setEntityLoadingConfig();
+
+        if (fromHardcodedProducers == null && producer == null) producer = entity;
+        checkState(fromHardcodedProducers != null ^ producer != null, "must specify one of %s (%s) or %s (%s)", 
+                PRODUCER.getName(), producer, FROM_HARDCODED_PRODUCERS.getName(), fromHardcodedProducers);
+
+        if (fromHardcodedProducers != null) {
+            for (Entity producer : Iterables.filter(fromHardcodedProducers, entityFilter)) {
+                addProducerHardcoded(producer);
+            }
+        }
+        
+        if (isAggregatingMembers()) {
+            setEntityBeforeSubscribingProducerMemberEvents(entity);
+            setEntitySubscribeProducerMemberEvents();
+            setEntityAfterSubscribingProducerMemberEvents();
+        }
+        
+        if (isAggregatingChildren()) {
+            setEntityBeforeSubscribingProducerChildrenEvents();
+            setEntitySubscribingProducerChildrenEvents();
+            setEntityAfterSubscribingProducerChildrenEvents();
+        }
+        
+        onUpdated();
+    }
+
+    @SuppressWarnings({ "unchecked" })
+    protected void setEntityLoadingConfig() {
+        this.producer = getConfig(PRODUCER);
+        this.fromHardcodedProducers= getConfig(FROM_HARDCODED_PRODUCERS);
+        this.defaultMemberValue = (T) getConfig(DEFAULT_MEMBER_VALUE);
+        this.fromMembers = Maybe.fromNullable(getConfig(FROM_MEMBERS)).or(fromMembers);
+        this.fromChildren = Maybe.fromNullable(getConfig(FROM_CHILDREN)).or(fromChildren);
+        this.entityFilter = (Predicate<? super Entity>) (getConfig(ENTITY_FILTER) == null ? Predicates.alwaysTrue() : getConfig(ENTITY_FILTER));
+        this.valueFilter = (Predicate<? super T>) (getConfig(VALUE_FILTER) == null ? getDefaultValueFilter() : getConfig(VALUE_FILTER));
+        
+        setEntityLoadingTargetConfig();
+    }
+    
+    protected Predicate<?> getDefaultValueFilter() {
+        return Predicates.alwaysTrue();
+    }
+
+    @SuppressWarnings({ "unchecked" })
+    protected void setEntityLoadingTargetConfig() {
+        this.targetSensor = (Sensor<U>) getRequiredConfig(TARGET_SENSOR);
+    }
+
+    protected void setEntityBeforeSubscribingProducerMemberEvents(EntityLocal entity) {
+        checkState(producer instanceof Group, "Producer must be a group when fromMembers true: producer=%s; entity=%s; "
+                + "hardcodedProducers=%s", getConfig(PRODUCER), entity, fromHardcodedProducers);
+    }
+
+    protected void setEntitySubscribeProducerMemberEvents() {
+        subscribe(producer, Changeable.MEMBER_ADDED, new SensorEventListener<Entity>() {
+            @Override public void onEvent(SensorEvent<Entity> event) {
+                if (entityFilter.apply(event.getValue())) {
+                    addProducerMember(event.getValue());
+                    onUpdated();
+                }
+            }
+        });
+        subscribe(producer, Changeable.MEMBER_REMOVED, new SensorEventListener<Entity>() {
+            @Override public void onEvent(SensorEvent<Entity> event) {
+                removeProducer(event.getValue());
+                onUpdated();
+            }
+        });
+    }
+
+    protected void setEntityAfterSubscribingProducerMemberEvents() {
+        if (producer instanceof Group) {
+            for (Entity member : Iterables.filter(((Group)producer).getMembers(), entityFilter)) {
+                addProducerMember(member);
+            }
+        }
+    }
+
+    protected void setEntityBeforeSubscribingProducerChildrenEvents() {
+    }
+
+    protected void setEntitySubscribingProducerChildrenEvents() {
+        subscribe(producer, AbstractEntity.CHILD_REMOVED, new SensorEventListener<Entity>() {
+            @Override public void onEvent(SensorEvent<Entity> event) {
+                removeProducer(event.getValue());
+                onUpdated();
+            }
+        });
+        subscribe(producer, AbstractEntity.CHILD_ADDED, new SensorEventListener<Entity>() {
+            @Override public void onEvent(SensorEvent<Entity> event) {
+                if (entityFilter.apply(event.getValue())) {
+                    addProducerChild(event.getValue());
+                    onUpdated();
+                }
+            }
+        });
+    }
+
+    protected void setEntityAfterSubscribingProducerChildrenEvents() {
+        for (Entity child : Iterables.filter(producer.getChildren(), entityFilter)) {
+            addProducerChild(child);
+        }
+    }
+
+    /** true if this should aggregate members */
+    protected boolean isAggregatingMembers() {
+        if (Boolean.TRUE.equals(fromMembers)) return true;
+        if (Boolean.TRUE.equals(fromChildren)) return false;
+        if (fromHardcodedProducers!=null) return false;
+        if (producer instanceof Group) return true;
+        return false;
+    }
+    
+    /** true if this should aggregate members */
+    protected boolean isAggregatingChildren() {
+        if (Boolean.TRUE.equals(fromChildren)) return true;
+        if (Boolean.TRUE.equals(fromMembers)) return false;
+        if (fromHardcodedProducers!=null) return false;
+        if (producer instanceof Group) return false;
+        return true;
+    }
+    
+    protected abstract void addProducerHardcoded(Entity producer);
+    protected abstract void addProducerMember(Entity producer);
+    protected abstract void addProducerChild(Entity producer);
+    
+    // TODO If producer removed but then get (queued) event from it after this method returns,  
+    protected void removeProducer(Entity producer) {
+        if (LOG.isDebugEnabled()) LOG.debug("{} stopped listening to {}", new Object[] {this, producer });
+        unsubscribe(producer);
+        onProducerRemoved(producer);
+    }
+
+    protected abstract void onProducerAdded(Entity producer);
+
+    protected abstract void onProducerRemoved(Entity producer);
+
+
+    /**
+     * 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 aggregate for enricher "+this, t);
+            throw Exceptions.propagate(t);
+        }
+    }
+
+    protected abstract Object compute();
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/enricher/stock/AbstractMultipleSensorAggregator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/AbstractMultipleSensorAggregator.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/AbstractMultipleSensorAggregator.java
new file mode 100644
index 0000000..1d76168
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/AbstractMultipleSensorAggregator.java
@@ -0,0 +1,169 @@
+/*
+ * 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.enricher.stock;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.brooklyn.api.entity.Entity;
+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.core.BrooklynLogging;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.flags.TypeCoercions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+
+/** Building on {@link AbstractAggregator} for a single source sensor (on multiple children and/or members) */
+public abstract class AbstractMultipleSensorAggregator<U> extends AbstractAggregator<Object,U> implements SensorEventListener<Object> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractMultipleSensorAggregator.class);
+
+    
+    /** access via {@link #getValues(Sensor)} */
+    private final Map<String, Map<Entity,Object>> values = Collections.synchronizedMap(new LinkedHashMap<String, Map<Entity,Object>>());
+
+    public AbstractMultipleSensorAggregator() {}
+
+    protected abstract Collection<Sensor<?>> getSourceSensors();
+    
+    @Override
+    protected void setEntityLoadingConfig() {
+        super.setEntityLoadingConfig();
+        Preconditions.checkNotNull(getSourceSensors(), "sourceSensors must be set");
+    }
+    
+    @Override
+    protected void setEntityBeforeSubscribingProducerChildrenEvents() {
+        BrooklynLogging.log(LOG, BrooklynLogging.levelDebugOrTraceIfReadOnly(producer),
+            "{} subscribing to children of {}", this, producer);
+        for (Sensor<?> sourceSensor: getSourceSensors()) {
+            subscribeToChildren(producer, sourceSensor, this);
+        }
+    }
+
+    @Override
+    protected void addProducerHardcoded(Entity producer) {
+        for (Sensor<?> sourceSensor: getSourceSensors()) {
+            subscribe(producer, sourceSensor, this);
+        }
+        onProducerAdded(producer);
+    }
+
+    @Override
+    protected void addProducerChild(Entity producer) {
+        // no `subscribe` call needed here, due to previous subscribeToChildren call
+        onProducerAdded(producer);
+    }
+
+    @Override
+    protected void addProducerMember(Entity producer) {
+        addProducerHardcoded(producer);
+    }
+
+    @Override
+    protected void onProducerAdded(Entity producer) {
+        BrooklynLogging.log(LOG, BrooklynLogging.levelDebugOrTraceIfReadOnly(producer),
+            "{} listening to {}", this, producer);
+        synchronized (values) {
+            for (Sensor<?> sensor: getSourceSensors()) {
+                Map<Entity,Object> vs = values.get(sensor.getName());
+                if (vs==null) {
+                    vs = new LinkedHashMap<Entity,Object>();
+                    values.put(sensor.getName(), vs);
+                }
+                
+                Object vo = vs.get(producer);
+                if (vo==null) {
+                    Object initialVal;
+                    if (sensor instanceof AttributeSensor) {
+                        initialVal = producer.getAttribute((AttributeSensor<?>)sensor);
+                    } else {
+                        initialVal = null;
+                    }
+                    vs.put(producer, initialVal != null ? initialVal : defaultMemberValue);
+                    // NB: see notes on possible race, in Aggregator#onProducerAdded
+                }
+                
+            }
+        }
+    }
+    
+    @Override
+    protected void onProducerRemoved(Entity producer) {
+        synchronized (values) {
+            for (Sensor<?> sensor: getSourceSensors()) {
+                Map<Entity,Object> vs = values.get(sensor.getName());
+                if (vs!=null)
+                    vs.remove(producer);
+            }
+        }
+        onUpdated();
+    }
+
+    @Override
+    public void onEvent(SensorEvent<Object> event) {
+        Entity e = event.getSource();
+        synchronized (values) {
+            Map<Entity,Object> vs = values.get(event.getSensor().getName());
+            if (vs==null) {
+                LOG.debug(this+" received event when no entry for sensor ("+event+"); likely just added or removed, and will initialize subsequently if needed");
+            } else {
+                vs.put(e, event.getValue());
+            }
+        }
+        onUpdated();
+    }
+
+    public <T> Map<Entity,T> getValues(Sensor<T> sensor) {
+        Map<Entity, T> valuesCopy = copyValues(sensor);
+        return coerceValues(valuesCopy, sensor.getType());
+    }
+
+    private <T> Map<Entity, T> coerceValues(Map<Entity, T> values, Class<? super T> type) {
+        Map<Entity, T> typedValues = MutableMap.of();
+        for (Entry<Entity, T> entry : values.entrySet()) {
+            @SuppressWarnings("unchecked")
+            T typedValue = (T) TypeCoercions.coerce(entry.getValue(), type);
+            typedValues.put(entry.getKey(), typedValue);
+        }
+        return typedValues;
+    }
+
+    private <T> Map<Entity, T> copyValues(Sensor<T> sensor) {
+        synchronized (values) {
+            @SuppressWarnings("unchecked")
+            Map<Entity, T> sv = (Map<Entity, T>) values.get(sensor.getName());
+            //use MutableMap because of potentially null values
+            return MutableMap.copyOf(sv).asUnmodifiable();
+        }
+    }
+    
+    @Override
+    protected abstract Object compute();
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/enricher/stock/AbstractTransformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/AbstractTransformer.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/AbstractTransformer.java
new file mode 100644
index 0000000..ab41c1a
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/AbstractTransformer.java
@@ -0,0 +1,101 @@
+/*
+ * 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.enricher.stock;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.api.sensor.SensorEvent;
+import org.apache.brooklyn.api.sensor.SensorEventListener;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
+import org.apache.brooklyn.core.sensor.BasicSensorEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Function;
+import com.google.common.reflect.TypeToken;
+
+@SuppressWarnings("serial")
+public abstract class AbstractTransformer<T,U> extends AbstractEnricher implements SensorEventListener<T> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractTransformer.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");
+    
+    protected Entity producer;
+    protected Sensor<T> sourceSensor;
+    protected Sensor<U> targetSensor;
+
+    public AbstractTransformer() {
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Override
+    public void setEntity(EntityLocal entity) {
+        super.setEntity(entity);
+
+        Function<SensorEvent<T>, U> transformation = getTransformation();
+        this.producer = getConfig(PRODUCER) == null ? entity: getConfig(PRODUCER);
+        this.sourceSensor = (Sensor<T>) getRequiredConfig(SOURCE_SENSOR);
+        Sensor<?> targetSensorSpecified = getConfig(TARGET_SENSOR);
+        this.targetSensor = targetSensorSpecified!=null ? (Sensor<U>) targetSensorSpecified : (Sensor<U>) this.sourceSensor;
+        if (producer.equals(entity) && targetSensorSpecified==null) {
+            LOG.error("Refusing to add an enricher which reads and publishes on the same sensor: "+
+                producer+"."+sourceSensor+" (computing "+transformation+")");
+            // we don't throw because this error may manifest itself after a lengthy deployment, 
+            // and failing it at that point simply because of an enricher is not very pleasant
+            // (at least not until we have good re-run support across the board)
+            return;
+        }
+        
+        subscribe(producer, sourceSensor, this);
+        
+        if (sourceSensor instanceof AttributeSensor) {
+            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));
+            }
+        }
+    }
+
+    /** returns a function for transformation, for immediate use only (not for caching, as it may change) */
+    protected abstract Function<SensorEvent<T>, U> getTransformation();
+
+    @Override
+    public void onEvent(SensorEvent<T> event) {
+        emit(targetSensor, compute(event));
+    }
+
+    protected Object compute(SensorEvent<T> event) {
+        // transformation is not going to change, but this design makes it easier to support changing config in future. 
+        // if it's an efficiency hole we can switch to populate the transformation at start.
+        U result = getTransformation().apply(event);
+        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/enricher/stock/AbstractTransformingEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/AbstractTransformingEnricher.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/AbstractTransformingEnricher.java
new file mode 100644
index 0000000..a29cc7b
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/AbstractTransformingEnricher.java
@@ -0,0 +1,38 @@
+/*
+ * 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.enricher.stock;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.sensor.Sensor;
+
+/**
+ * Convenience base for transforming a single sensor into a single new sensor of the same type
+ * 
+ * @deprecated since 0.7.0; use {@link Enrichers.builder()}
+ */
+public abstract class AbstractTransformingEnricher<T> extends AbstractTypeTransformingEnricher<T,T> {
+
+    public AbstractTransformingEnricher() { // for rebinding
+    }
+    
+    public AbstractTransformingEnricher(Entity producer, Sensor<T> source, Sensor<T> target) {
+        super(producer, source, target);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/enricher/stock/AbstractTypeTransformingEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/AbstractTypeTransformingEnricher.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/AbstractTypeTransformingEnricher.java
new file mode 100644
index 0000000..1469829
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/AbstractTypeTransformingEnricher.java
@@ -0,0 +1,68 @@
+/*
+ * 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.enricher.stock;
+
+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.SensorEventListener;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
+import org.apache.brooklyn.core.sensor.BasicSensorEvent;
+import org.apache.brooklyn.util.core.flags.SetFromFlag;
+
+/**
+ * Convenience base for transforming a single sensor into a single new sensor of the same type
+ * 
+ * @deprecated since 0.7.0; use {@link Enrichers.builder()}
+ */
+public abstract class AbstractTypeTransformingEnricher<T,U> extends AbstractEnricher implements SensorEventListener<T> {
+    
+    @SetFromFlag
+    private Entity producer;
+    
+    @SetFromFlag
+    private Sensor<T> source;
+    
+    @SetFromFlag
+    protected Sensor<U> target;
+
+    public AbstractTypeTransformingEnricher() { // for rebind
+    }
+    
+    public AbstractTypeTransformingEnricher(Entity producer, Sensor<T> source, Sensor<U> target) {
+        this.producer = producer;
+        this.source = source;
+        this.target = target;
+    }
+    
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public void setEntity(EntityLocal entity) {
+        super.setEntity(entity);
+        if (producer==null) producer = entity;
+        subscribe(producer, source, this);
+        
+        if (source instanceof AttributeSensor) {
+            Object value = producer.getAttribute((AttributeSensor)source);
+            // TODO Aled didn't you write a convenience to "subscribeAndRunIfSet" ? (-Alex)
+            if (value!=null)
+                onEvent(new BasicSensorEvent(source, producer, value, -1));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/enricher/stock/AddingEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/AddingEnricher.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/AddingEnricher.java
new file mode 100644
index 0000000..941d745
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/AddingEnricher.java
@@ -0,0 +1,107 @@
+/*
+ * 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.enricher.stock;
+
+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.core.enricher.AbstractEnricher;
+import org.apache.brooklyn.core.sensor.BasicSensorEvent;
+
+/** 
+ * enricher which adds multiple sensors on an entity to produce a new sensor
+ * 
+ * Instead, consider calling:
+ * <pre>
+ * {@code
+ * addEnricher(Enrichers.builder()
+ *         .combining(sources)
+ *         .publishing(target)
+ *         .computeSum()
+ *         .build());
+ * }
+ * </pre>
+ * <p>
+ * 
+ * @deprecated since 0.7.0; use {@link Enrichers.builder()}
+ * @see Combiner if need to sub-class
+ */
+public class AddingEnricher extends AbstractEnricher implements SensorEventListener {
+
+    private Sensor[] sources;
+    private Sensor<? extends Number> target;
+
+    public AddingEnricher(Sensor sources[], Sensor<? extends Number> target) {
+        this.sources = sources;
+        this.target = target;
+    }
+
+    public void setEntity(EntityLocal entity) {
+        super.setEntity(entity);
+        
+        for (Sensor source: sources) {
+            subscribe(entity, source, this);
+            if (source instanceof AttributeSensor) {
+                Object value = entity.getAttribute((AttributeSensor)source);
+                if (value!=null)
+                    onEvent(new BasicSensorEvent(source, entity, value, -1));
+            }
+        }
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Override
+    public void onEvent(SensorEvent event) {
+        Number value = recompute();
+        Number typedValue = cast(value, (Class<? extends Number>)target.getType());
+        if (target instanceof AttributeSensor) {
+            entity.setAttribute((AttributeSensor)target, typedValue);
+        } else if (typedValue!=null)
+            entity.emit((Sensor)target, typedValue);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <V> V cast(Number value, Class<V> type) {
+        if (value==null) return null;
+        if (type.isInstance(value)) return (V)value;
+        
+        if (type==Integer.class) return (V) (Integer) (int)Math.round(value.doubleValue());
+        if (type==Long.class) return (V) (Long) Math.round(value.doubleValue());
+        if (type==Double.class) return (V) (Double) value.doubleValue();
+        if (type==Float.class) return (V) (Float) value.floatValue();
+        if (type==Byte.class) return (V) (Byte) (byte)Math.round(value.doubleValue());
+        if (type==Short.class) return (V) (Short) (short)Math.round(value.doubleValue());
+        
+        throw new UnsupportedOperationException("conversion of mathematical operation to "+type+" not supported");
+    }
+
+    protected Number recompute() {
+        if (sources.length==0) return null;
+        Double result = 0d;
+        for (Sensor source: sources) {
+            Object value = entity.getAttribute((AttributeSensor) source);
+            if (value==null) return null;
+            result += ((Number)value).doubleValue();
+        }
+        return result;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/enricher/stock/Aggregator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/Aggregator.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/Aggregator.java
new file mode 100644
index 0000000..e42d2cb
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/Aggregator.java
@@ -0,0 +1,222 @@
+/*
+ * 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.enricher.stock;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import org.apache.brooklyn.api.entity.Entity;
+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.BrooklynLogging;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.enricher.stock.Enrichers.ComputingAverage;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.flags.SetFromFlag;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.text.StringPredicates;
+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;
+
+/** Building on {@link AbstractAggregator} for a single source sensor (on multiple children and/or members) */
+@SuppressWarnings("serial")
+//@Catalog(name="Aggregator", description="Aggregates attributes from multiple entities into a single attribute value; see Enrichers.builder().aggregating(...)")
+public class Aggregator<T,U> extends AbstractAggregator<T,U> implements SensorEventListener<T> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Aggregator.class);
+
+    public static final ConfigKey<Sensor<?>> SOURCE_SENSOR = ConfigKeys.newConfigKey(new TypeToken<Sensor<?>>() {}, "enricher.sourceSensor");
+    
+    @SetFromFlag("transformation")
+    public static final ConfigKey<Object> TRANSFORMATION_UNTYPED = ConfigKeys.newConfigKey(Object.class, "enricher.transformation.untyped",
+        "Specifies a transformation, as a function from a collection to the value, or as a string matching a pre-defined named transformation, "
+        + "such as 'average' (for numbers), 'sum' (for numbers), or 'list' (the default, putting any collection of items into a list)");
+    public static final ConfigKey<Function<? super Collection<?>, ?>> TRANSFORMATION = ConfigKeys.newConfigKey(new TypeToken<Function<? super Collection<?>, ?>>() {}, "enricher.transformation");
+    
+    public static final ConfigKey<Boolean> EXCLUDE_BLANK = ConfigKeys.newBooleanConfigKey("enricher.aggregator.excludeBlank", "Whether explicit nulls or blank strings should be excluded (default false); this only applies if no value filter set", false);
+
+    protected Sensor<T> sourceSensor;
+    protected Function<? super Collection<T>, ? extends U> transformation;
+    
+    /**
+     * 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<Entity, T> values = Collections.synchronizedMap(new LinkedHashMap<Entity, T>());
+
+    public Aggregator() {}
+
+    @SuppressWarnings("unchecked")
+    protected void setEntityLoadingConfig() {
+        super.setEntityLoadingConfig();
+        this.sourceSensor = (Sensor<T>) getRequiredConfig(SOURCE_SENSOR);
+        
+        this.transformation = (Function<? super Collection<T>, ? extends U>) config().get(TRANSFORMATION);
+        
+        Object t1 = config().get(TRANSFORMATION_UNTYPED);
+        Function<? super Collection<?>, ?> t2 = null;
+        if (t1 instanceof String) {
+            t2 = lookupTransformation((String)t1);
+            if (t2==null) {
+                LOG.warn("Unknown transformation '"+t1+"' for "+this+"; will use default transformation");
+            }
+        }
+        
+        if (this.transformation==null) {
+            this.transformation = (Function<? super Collection<T>, ? extends U>) t2;
+        } else if (t1!=null && !Objects.equals(t2, this.transformation)) {
+            throw new IllegalStateException("Cannot supply both "+TRANSFORMATION_UNTYPED+" and "+TRANSFORMATION+" unless they are equal.");
+        }
+    }
+        
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    protected Function<? super Collection<?>, ?> lookupTransformation(String t1) {
+        if ("average".equalsIgnoreCase(t1)) return new Enrichers.ComputingAverage(null, null, targetSensor.getTypeToken());
+        if ("sum".equalsIgnoreCase(t1)) return new Enrichers.ComputingAverage(null, null, targetSensor.getTypeToken());
+        if ("list".equalsIgnoreCase(t1)) return new ComputingList();
+        return null;
+    }
+
+    private class ComputingList<TT> implements Function<Collection<TT>, List<TT>> {
+        @Override
+        public List<TT> apply(Collection<TT> input) {
+            if (input==null) return null;
+            return MutableList.copyOf(input).asUnmodifiable();
+        }
+        
+    }
+    
+    @Override
+    protected void setEntityBeforeSubscribingProducerChildrenEvents() {
+        BrooklynLogging.log(LOG, BrooklynLogging.levelDebugOrTraceIfReadOnly(producer),
+            "{} subscribing to children of {}", this, producer);
+        subscribeToChildren(producer, sourceSensor, this);
+    }
+
+    @Override
+    protected void addProducerHardcoded(Entity producer) {
+        subscribe(producer, sourceSensor, this);
+        onProducerAdded(producer);
+    }
+
+    @Override
+    protected void addProducerChild(Entity producer) {
+        // no subscription needed here, due to the subscribeToChildren call
+        onProducerAdded(producer);
+    }
+
+    @Override
+    protected void addProducerMember(Entity producer) {
+        subscribe(producer, sourceSensor, this);
+        onProducerAdded(producer);
+    }
+
+    @Override
+    protected void onProducerAdded(Entity producer) {
+        BrooklynLogging.log(LOG, BrooklynLogging.levelDebugOrTraceIfReadOnly(producer),
+            "{} listening to {}", this, producer);
+        synchronized (values) {
+            T vo = values.get(producer);
+            if (vo==null) {
+                T initialVal;
+                if (sourceSensor instanceof AttributeSensor) {
+                    initialVal = producer.getAttribute((AttributeSensor<T>)sourceSensor);
+                } else {
+                    initialVal = null;
+                }
+                values.put(producer, initialVal != null ? initialVal : defaultMemberValue);
+                //we might skip in onEvent in the short window while !values.containsKey(producer)
+                //but that's okay because the put which would have been done there is done here now
+            } else {
+                //vo will be null unless some weird race with addProducer+removeProducer is occuring
+                //(and that's something we can tolerate i think)
+                if (LOG.isDebugEnabled()) LOG.debug("{} already had value ({}) for producer ({}); but that producer has just been added", new Object[] {this, vo, producer});
+            }
+        }
+    }
+    
+    @Override
+    protected Predicate<?> getDefaultValueFilter() {
+        if (getConfig(EXCLUDE_BLANK))
+            return StringPredicates.isNonBlank();
+        else
+            return Predicates.alwaysTrue();
+    }
+    
+    @Override
+    protected void onProducerRemoved(Entity producer) {
+        values.remove(producer);
+        onUpdated();
+    }
+
+    @Override
+    public void onEvent(SensorEvent<T> event) {
+        Entity e = event.getSource();
+        synchronized (values) {
+            if (values.containsKey(e)) {
+                values.put(e, event.getValue());
+            } else {
+                if (LOG.isDebugEnabled()) LOG.debug("{} received event for unknown producer ({}); presumably that producer has recently been removed", this, e);
+            }
+        }
+        onUpdated();
+    }
+
+    protected void onUpdated() {
+        try {
+            emit(targetSensor, compute());
+        } catch (Throwable t) {
+            LOG.warn("Error calculating and setting aggregate for enricher "+this, t);
+            throw Exceptions.propagate(t);
+        }
+    }
+    
+    @Override
+    protected Object compute() {
+        synchronized (values) {
+            // TODO Could avoid copying when filter not needed
+            List<T> vs = MutableList.copyOf(Iterables.filter(values.values(), valueFilter));
+            if (transformation==null) return vs;
+            return transformation.apply(vs);
+        }
+    }
+    
+    protected Map<Entity, T> copyOfValues() {
+        // Don't use ImmutableMap, as can contain null values
+        synchronized (values) {
+            return Collections.unmodifiableMap(MutableMap.copyOf(values));
+        }
+    }
+
+}


[11/36] incubator-brooklyn git commit: Rename o.a.b.sensor.core to o.a.b.core.sensor

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/test/java/org/apache/brooklyn/entity/java/EntityPollingTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/java/EntityPollingTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/java/EntityPollingTest.java
index f5b9e5a..17b7f15 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/java/EntityPollingTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/java/EntityPollingTest.java
@@ -24,6 +24,7 @@ import javax.management.ObjectName;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.entity.java.VanillaJavaAppImpl;
@@ -31,7 +32,6 @@ import org.apache.brooklyn.entity.java.VanillaJavaAppSshDriver;
 import org.apache.brooklyn.entity.java.UsesJmx.JmxAgentModes;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.software.base.test.jmx.JmxService;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
 import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;
 import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;
 import org.apache.brooklyn.test.EntityTestUtils;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/test/java/org/apache/brooklyn/entity/java/VanillaJavaAppRebindTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/java/VanillaJavaAppRebindTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/java/VanillaJavaAppRebindTest.java
index 2bcb978..d10f43a 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/java/VanillaJavaAppRebindTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/java/VanillaJavaAppRebindTest.java
@@ -27,12 +27,12 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
 import org.apache.brooklyn.core.mgmt.rebind.RebindTestUtils;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.entity.java.VanillaJavaApp;
 import org.apache.brooklyn.entity.java.VanillaJavaAppImpl;
 import org.apache.brooklyn.entity.java.JavaOptsTest.TestingJavaOptsVanillaJavaAppImpl;
 import org.apache.brooklyn.policy.enricher.RollingTimeWindowMeanEnricher;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.ResourceUtils;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessEntityLatchTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessEntityLatchTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessEntityLatchTest.java
index 6910154..6da0269 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessEntityLatchTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessEntityLatchTest.java
@@ -33,6 +33,7 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessEntityTest.MyService;
@@ -44,7 +45,6 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 import org.apache.brooklyn.location.byon.FixedListMachineProvisioningLocation;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.core.task.TaskInternal;
 import org.apache.brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessEntityTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessEntityTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessEntityTest.java
index 0b1515b..2b5ec4a 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessEntityTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessEntityTest.java
@@ -54,6 +54,7 @@ import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.location.Locations;
 import org.apache.brooklyn.core.location.SimulatedLocation;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.entity.software.base.AbstractSoftwareProcessSshDriver;
@@ -68,7 +69,6 @@ import org.apache.brooklyn.entity.software.base.SoftwareProcess.StopSoftwarePara
 import org.apache.brooklyn.entity.software.base.SoftwareProcess.RestartSoftwareParameters.RestartMachineMode;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess.StopSoftwareParameters.StopMode;
 import org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasksTest;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.collections.MutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/test/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasksTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasksTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasksTest.java
index 117540c..d336ad0 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasksTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasksTest.java
@@ -33,6 +33,8 @@ import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
@@ -40,8 +42,6 @@ import org.apache.brooklyn.entity.software.base.SoftwareProcess.StopSoftwarePara
 import org.apache.brooklyn.entity.stock.BasicEntity;
 import org.apache.brooklyn.entity.stock.BasicEntityImpl;
 import org.apache.brooklyn.location.jclouds.BailOutJcloudsLocation;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.core.task.TaskInternal;
 import org.apache.brooklyn.util.core.task.ValueResolver;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/sensor/core/PortAttributeSensorAndConfigKeyTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/sensor/core/PortAttributeSensorAndConfigKeyTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/sensor/core/PortAttributeSensorAndConfigKeyTest.java
index f1889a0..179a6f4 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/sensor/core/PortAttributeSensorAndConfigKeyTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/sensor/core/PortAttributeSensorAndConfigKeyTest.java
@@ -24,13 +24,13 @@ import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess;
 import org.apache.brooklyn.entity.software.base.EmptySoftwareProcessImpl;
 import org.testng.annotations.Test;
 import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
 
 import com.google.common.collect.ImmutableList;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/ssh/SshCommandIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/ssh/SshCommandIntegrationTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/ssh/SshCommandIntegrationTest.java
index 8f7b6bf..c57711f 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/ssh/SshCommandIntegrationTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/ssh/SshCommandIntegrationTest.java
@@ -30,9 +30,9 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.ssh.SshCommandEffector;
 import org.apache.brooklyn.sensor.ssh.SshCommandSensor;
 import org.apache.brooklyn.test.EntityTestUtils;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/JmxFeedTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/JmxFeedTest.java b/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/JmxFeedTest.java
index bf2cdf9..8f722b2 100644
--- a/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/JmxFeedTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/JmxFeedTest.java
@@ -51,6 +51,9 @@ import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.PortRanges;
 import org.apache.brooklyn.core.location.SimulatedLocation;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestApplicationImpl;
 import org.apache.brooklyn.core.test.entity.TestEntity;
@@ -60,9 +63,6 @@ import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.entity.java.UsesJmx.JmxAgentModes;
 import org.apache.brooklyn.entity.software.base.test.jmx.GeneralisedDynamicMBean;
 import org.apache.brooklyn.entity.software.base.test.jmx.JmxService;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
-import org.apache.brooklyn.sensor.core.BasicNotificationSensor;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
 import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;
 import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/RebindJmxFeedTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/RebindJmxFeedTest.java b/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/RebindJmxFeedTest.java
index fb8f516..9ed0031 100644
--- a/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/RebindJmxFeedTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/RebindJmxFeedTest.java
@@ -31,13 +31,13 @@ import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.location.PortRanges;
 import org.apache.brooklyn.core.mgmt.rebind.RebindTestFixtureWithApp;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.core.test.entity.TestEntityImpl;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.entity.java.UsesJmx.JmxAgentModes;
 import org.apache.brooklyn.entity.software.base.test.jmx.GeneralisedDynamicMBean;
 import org.apache.brooklyn.entity.software.base.test.jmx.JmxService;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
 import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;
 import org.apache.brooklyn.sensor.feed.jmx.JmxFeed;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/database/src/main/java/org/apache/brooklyn/entity/database/DatastoreMixins.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/DatastoreMixins.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/DatastoreMixins.java
index c2acfab..534c0eb 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/DatastoreMixins.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/DatastoreMixins.java
@@ -28,7 +28,7 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.effector.Effectors;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.stream.KnownSizeInputStream;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNode.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNode.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNode.java
index cdcbefb..f22381a 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNode.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNode.java
@@ -24,15 +24,15 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
 import org.apache.brooklyn.entity.java.UsesJava;
 import org.apache.brooklyn.entity.java.UsesJavaMXBeans;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.AttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 @ImplementedBy(CrateNodeImpl.class)

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbNode.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbNode.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbNode.java
index 4063aef..3c78d99 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbNode.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbNode.java
@@ -27,13 +27,13 @@ import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.config.MapConfigKey;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.database.DatabaseNode;
 import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 @Catalog(name="MariaDB Node", description="MariaDB is an open source relational database management system (RDBMS)", iconUrl="classpath:///mariadb-logo-180x119.png")

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlCluster.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlCluster.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlCluster.java
index 955bde6..d860d04 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlCluster.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlCluster.java
@@ -25,13 +25,13 @@ import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 
 import com.google.common.reflect.TypeToken;
 
 import org.apache.brooklyn.entity.database.DatastoreMixins.HasDatastoreUrl;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.sensor.core.Sensors;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 
 @ImplementedBy(MySqlClusterImpl.class)
 @Catalog(name="MySql Master-Slave cluster", description="Sets up a cluster of MySQL nodes using master-slave relation and binary logging", iconUrl="classpath:///mysql-logo-110x57.png")

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterImpl.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterImpl.java
index 2d28ac7..e106728 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterImpl.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterImpl.java
@@ -36,9 +36,9 @@ import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.EntityPredicates;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceNotUpLogic;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.group.DynamicClusterImpl;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.sensor.feed.function.FunctionFeed;
 import org.apache.brooklyn.sensor.feed.function.FunctionPollConfig;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNode.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNode.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNode.java
index aa11eb4..484606e 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNode.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNode.java
@@ -30,12 +30,12 @@ import org.apache.brooklyn.core.config.MapConfigKey;
 import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 @Catalog(name="MySql Node", description="MySql is an open source relational database management system (RDBMS)", iconUrl="classpath:///mysql-logo-110x57.png")

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNode.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNode.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNode.java
index 6cb9cde..cd97719 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNode.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNode.java
@@ -26,12 +26,12 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.database.DatabaseNode;
 import org.apache.brooklyn.entity.database.DatastoreMixins;
 import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
index f9e80f7..5ff70fe 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
@@ -41,8 +41,8 @@ import javax.annotation.Nullable;
 import org.apache.brooklyn.api.location.OsDetails;
 import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.task.DynamicTasks;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/database/src/main/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepNode.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepNode.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepNode.java
index 608b45d..e6580bb 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepNode.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepNode.java
@@ -24,12 +24,12 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.database.DatastoreMixins;
 import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 @Catalog(name = "RubyRep Node", description = "RubyRep is a database replication system", iconUrl = "classpath:///rubyrep-logo.jpeg")

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/database/src/main/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepNodeImpl.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepNodeImpl.java
index 8340794..429c7aa 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepNodeImpl.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepNodeImpl.java
@@ -21,9 +21,9 @@ package org.apache.brooklyn.entity.database.rubyrep;
 import java.net.URI;
 
 import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
 import org.apache.brooklyn.util.time.Duration;
 
 public class RubyRepNodeImpl extends SoftwareProcessImpl implements RubyRepNode {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/MessageBroker.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/MessageBroker.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/MessageBroker.java
index 5718aaf..23260d2 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/MessageBroker.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/MessageBroker.java
@@ -20,7 +20,7 @@ package org.apache.brooklyn.entity.messaging;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.Sensors;
 
 /**
  * Marker interface identifying message brokers.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/Queue.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/Queue.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/Queue.java
index cfe2ab2..190d5bf 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/Queue.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/Queue.java
@@ -19,8 +19,8 @@
 package org.apache.brooklyn.entity.messaging;
 
 import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 
 /**
  * An interface that describes a messaging queue.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/Topic.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/Topic.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/Topic.java
index f4d2539..c4ed3b7 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/Topic.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/Topic.java
@@ -18,7 +18,7 @@
  */
 package org.apache.brooklyn.entity.messaging;
 
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
 
 /**
  * An interface that describes a messaging topic.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQBroker.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQBroker.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQBroker.java
index b52306e..aa79613 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQBroker.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQBroker.java
@@ -24,14 +24,14 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.BasicConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.entity.messaging.MessageBroker;
 import org.apache.brooklyn.entity.messaging.jms.JMSBroker;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.AttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.time.Duration;
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/amqp/AmqpExchange.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/amqp/AmqpExchange.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/amqp/AmqpExchange.java
index a188a6e..0d3171c 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/amqp/AmqpExchange.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/amqp/AmqpExchange.java
@@ -19,7 +19,7 @@
 package org.apache.brooklyn.entity.messaging.amqp;
 
 import org.apache.brooklyn.api.sensor.Sensor;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/amqp/AmqpServer.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/amqp/AmqpServer.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/amqp/AmqpServer.java
index 80638f2..80b49ee 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/amqp/AmqpServer.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/amqp/AmqpServer.java
@@ -20,8 +20,8 @@ package org.apache.brooklyn.entity.messaging.amqp;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.core.entity.Attributes;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
 
 /**
  * Marker interface identifying AMQP servers.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/Kafka.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/Kafka.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/Kafka.java
index 0d26997..6a2322c 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/Kafka.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/Kafka.java
@@ -21,8 +21,8 @@ package org.apache.brooklyn.entity.messaging.kafka;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaBroker.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaBroker.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaBroker.java
index c7d7829..1b54cdf 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaBroker.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaBroker.java
@@ -24,12 +24,12 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.BasicConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.entity.messaging.MessageBroker;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.zookeeper.ZooKeeperNode;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaCluster.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaCluster.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaCluster.java
index 4e48dc3..fba4e1c 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaCluster.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaCluster.java
@@ -29,11 +29,11 @@ import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
 import org.apache.brooklyn.core.entity.trait.Resizable;
 import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.group.Cluster;
 import org.apache.brooklyn.entity.group.DynamicCluster;
 import org.apache.brooklyn.entity.zookeeper.ZooKeeperNode;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaZooKeeper.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaZooKeeper.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaZooKeeper.java
index 8de5a5f..5aee6d2 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaZooKeeper.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaZooKeeper.java
@@ -23,9 +23,9 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.annotation.EffectorParam;
 import org.apache.brooklyn.core.config.BasicConfigKey;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.zookeeper.ZooKeeperNode;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidBroker.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidBroker.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidBroker.java
index 2d66ef5..89189f7 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidBroker.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidBroker.java
@@ -26,13 +26,13 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.BasicConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.entity.messaging.MessageBroker;
 import org.apache.brooklyn.entity.messaging.amqp.AmqpServer;
 import org.apache.brooklyn.entity.messaging.jms.JMSBroker;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitBroker.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitBroker.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitBroker.java
index c4190cd..fc4eddf 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitBroker.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitBroker.java
@@ -28,12 +28,12 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.BasicConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.messaging.MessageBroker;
 import org.apache.brooklyn.entity.messaging.amqp.AmqpServer;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/Storm.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/Storm.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/Storm.java
index 827a23d..9b927cd 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/Storm.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/Storm.java
@@ -25,12 +25,12 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.config.render.RendererHints;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.zookeeper.ZooKeeperEnsemble;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormSshDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormSshDriver.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormSshDriver.java
index 8236e5b..66578e6 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormSshDriver.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormSshDriver.java
@@ -28,13 +28,13 @@ import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.Machines;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.entity.java.JavaSoftwareProcessSshDriver;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.zookeeper.ZooKeeperEnsemble;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.net.Networking;
 import org.apache.brooklyn.util.os.Os;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperEnsemble.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperEnsemble.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperEnsemble.java
index ad4d6a6..a5ba570 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperEnsemble.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperEnsemble.java
@@ -25,9 +25,9 @@ import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 import com.google.common.reflect.TypeToken;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperNode.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperNode.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperNode.java
index 2de34f9..18cb6c6 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperNode.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperNode.java
@@ -23,10 +23,10 @@ import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/StormAbstractCloudLiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/StormAbstractCloudLiveTest.java b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/StormAbstractCloudLiveTest.java
index ef67a65..5633f74 100644
--- a/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/StormAbstractCloudLiveTest.java
+++ b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/StormAbstractCloudLiveTest.java
@@ -18,12 +18,12 @@
  */
 package org.apache.brooklyn.entity.messaging.storm;
 
+import static org.apache.brooklyn.core.sensor.DependentConfiguration.attributeWhenReady;
 import static org.apache.brooklyn.entity.messaging.storm.Storm.NIMBUS_HOSTNAME;
 import static org.apache.brooklyn.entity.messaging.storm.Storm.ZOOKEEPER_ENSEMBLE;
 import static org.apache.brooklyn.entity.messaging.storm.Storm.Role.NIMBUS;
 import static org.apache.brooklyn.entity.messaging.storm.Storm.Role.SUPERVISOR;
 import static org.apache.brooklyn.entity.messaging.storm.Storm.Role.UI;
-import static org.apache.brooklyn.sensor.core.DependentConfiguration.attributeWhenReady;
 
 import java.io.File;
 import java.util.Map;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/monit/MonitNode.java
----------------------------------------------------------------------
diff --git a/software/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/monit/MonitNode.java b/software/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/monit/MonitNode.java
index fa61039..2e3798c 100644
--- a/software/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/monit/MonitNode.java
+++ b/software/monitoring/src/main/java/org/apache/brooklyn/entity/monitoring/monit/MonitNode.java
@@ -27,10 +27,10 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 import com.google.common.collect.ImmutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/monitoring/src/test/java/org/apache/brooklyn/entity/monitoring/monit/MonitIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/monitoring/src/test/java/org/apache/brooklyn/entity/monitoring/monit/MonitIntegrationTest.java b/software/monitoring/src/test/java/org/apache/brooklyn/entity/monitoring/monit/MonitIntegrationTest.java
index 2a26c6c..685f662 100644
--- a/software/monitoring/src/test/java/org/apache/brooklyn/entity/monitoring/monit/MonitIntegrationTest.java
+++ b/software/monitoring/src/test/java/org/apache/brooklyn/entity/monitoring/monit/MonitIntegrationTest.java
@@ -30,12 +30,12 @@ import java.util.concurrent.Callable;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.MachineDetails;
 import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport;
 import org.apache.brooklyn.entity.database.mysql.MySqlNode;
 import org.apache.brooklyn.entity.software.base.SameServerEntity;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/network/src/main/java/org/apache/brooklyn/entity/network/bind/BindDnsServer.java
----------------------------------------------------------------------
diff --git a/software/network/src/main/java/org/apache/brooklyn/entity/network/bind/BindDnsServer.java b/software/network/src/main/java/org/apache/brooklyn/entity/network/bind/BindDnsServer.java
index 96c56fb..f5b5e21 100644
--- a/software/network/src/main/java/org/apache/brooklyn/entity/network/bind/BindDnsServer.java
+++ b/software/network/src/main/java/org/apache/brooklyn/entity/network/bind/BindDnsServer.java
@@ -33,10 +33,10 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.group.DynamicGroup;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.net.Cidr;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/network/src/test/java/org/apache/brooklyn/entity/network/bind/PrefixAndIdEnricher.java
----------------------------------------------------------------------
diff --git a/software/network/src/test/java/org/apache/brooklyn/entity/network/bind/PrefixAndIdEnricher.java b/software/network/src/test/java/org/apache/brooklyn/entity/network/bind/PrefixAndIdEnricher.java
index 6a90e83..c32e2ce 100644
--- a/software/network/src/test/java/org/apache/brooklyn/entity/network/bind/PrefixAndIdEnricher.java
+++ b/software/network/src/test/java/org/apache/brooklyn/entity/network/bind/PrefixAndIdEnricher.java
@@ -24,7 +24,7 @@ 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.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
 
 import com.google.common.reflect.TypeToken;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenter.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenter.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenter.java
index 2f92c47..d9d2bbf 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenter.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenter.java
@@ -31,11 +31,11 @@ import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.effector.MethodEffector;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.nosql.cassandra.TokenGenerators.PosNeg63TokenGenerator;
 import org.apache.brooklyn.entity.database.DatastoreMixins;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNode.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNode.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNode.java
index b945bdd..d5c7e2f 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNode.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNode.java
@@ -31,13 +31,13 @@ import org.apache.brooklyn.core.config.BasicConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
 import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.database.DatastoreMixins;
 import org.apache.brooklyn.entity.java.UsesJavaMXBeans;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeImpl.java
index 0a7e638..d549776 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeImpl.java
@@ -41,14 +41,14 @@ import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.Machines;
 import org.apache.brooklyn.core.location.cloud.CloudLocationConfig;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.java.JavaAppUtils;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.policy.enricher.RollingTimeWindowMeanEnricher;
 import org.apache.brooklyn.policy.enricher.TimeWeightedDeltaEnricher;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.feed.function.FunctionFeed;
 import org.apache.brooklyn.sensor.feed.function.FunctionPollConfig;
 import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeSshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeSshDriver.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeSshDriver.java
index 11d919e..193b49f 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeSshDriver.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeSshDriver.java
@@ -36,6 +36,7 @@ import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.Machines;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -47,7 +48,6 @@ import org.apache.brooklyn.entity.database.DatastoreMixins;
 import org.apache.brooklyn.entity.java.JavaSoftwareProcessSshDriver;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.task.DynamicTasks;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseCluster.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseCluster.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseCluster.java
index 2ba961f..dfff6a4 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseCluster.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseCluster.java
@@ -28,8 +28,8 @@ import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
index bef9fa5..c065897 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
@@ -41,12 +41,12 @@ import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.entity.group.AbstractMembershipTrackingPolicy;
 import org.apache.brooklyn.entity.group.DynamicClusterImpl;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.sensor.feed.http.HttpFeed;
 import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNode.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNode.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNode.java
index b592af8..8bde2f3 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNode.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNode.java
@@ -31,10 +31,10 @@ import org.apache.brooklyn.core.config.render.RendererHints;
 import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.text.ByteSizeStrings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
index a5a821e..5da3c47 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
@@ -40,10 +40,10 @@ import org.apache.brooklyn.core.entity.drivers.downloads.BasicDownloadRequiremen
 import org.apache.brooklyn.core.entity.drivers.downloads.DownloadProducerFromUrlAttribute;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.entity.software.base.AbstractSoftwareProcessSshDriver;
 import org.apache.http.auth.UsernamePasswordCredentials;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
 import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.http.HttpTool;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseSyncGateway.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseSyncGateway.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseSyncGateway.java
index 9d7d000..9576549 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseSyncGateway.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseSyncGateway.java
@@ -23,10 +23,10 @@ import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 @ImplementedBy(CouchbaseSyncGatewayImpl.class)

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java
index 524e661..8a5a25e 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java
@@ -32,9 +32,9 @@ import org.apache.brooklyn.api.entity.drivers.downloads.DownloadResolver;
 import org.apache.brooklyn.api.location.OsDetails;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityPredicates;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.entity.software.base.AbstractSoftwareProcessSshDriver;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.ssh.BashCommands;
 import org.apache.brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchdb/CouchDBCluster.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchdb/CouchDBCluster.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchdb/CouchDBCluster.java
index 464e492..c341945 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchdb/CouchDBCluster.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchdb/CouchDBCluster.java
@@ -20,9 +20,9 @@ package org.apache.brooklyn.entity.nosql.couchdb;
 
 import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchdb/CouchDBNode.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchdb/CouchDBNode.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchdb/CouchDBNode.java
index dd7aef7..fa9506a 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchdb/CouchDBNode.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchdb/CouchDBNode.java
@@ -22,9 +22,9 @@ import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.webapp.WebAppService;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchCluster.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchCluster.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchCluster.java
index 116e18e..e0fbc7e 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchCluster.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchCluster.java
@@ -20,8 +20,8 @@ package org.apache.brooklyn.entity.nosql.elasticsearch;
 
 import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchNode.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchNode.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchNode.java
index 1cf108e..90d8d02 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchNode.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/elasticsearch/ElasticSearchNode.java
@@ -24,13 +24,13 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.webapp.WebAppServiceConstants;
 import org.apache.brooklyn.entity.database.DatastoreMixins;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/AbstractMongoDBServer.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/AbstractMongoDBServer.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/AbstractMongoDBServer.java
index 159314c..52e24d8 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/AbstractMongoDBServer.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/AbstractMongoDBServer.java
@@ -21,10 +21,10 @@ package org.apache.brooklyn.entity.nosql.mongodb;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.sensor.core.AttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 public interface AbstractMongoDBServer extends SoftwareProcess, Entity {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBClientSshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBClientSshDriver.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBClientSshDriver.java
index 5682bd0..bd5e552 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBClientSshDriver.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBClientSshDriver.java
@@ -25,11 +25,11 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.entity.nosql.mongodb.sharding.MongoDBRouter;
 import org.apache.brooklyn.entity.nosql.mongodb.sharding.MongoDBRouterCluster;
 import org.apache.brooklyn.entity.nosql.mongodb.sharding.MongoDBShardedDeployment;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.math.MathPredicates;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBReplicaSet.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBReplicaSet.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBReplicaSet.java
index f057d46..14d0eb8 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBReplicaSet.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBReplicaSet.java
@@ -25,9 +25,9 @@ import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.group.Cluster;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 import com.google.common.reflect.TypeToken;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBServer.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBServer.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBServer.java
index 6c33c3c..2ec38dc 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBServer.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBServer.java
@@ -26,8 +26,8 @@ import org.apache.brooklyn.api.sensor.AttributeSensor.SensorPersistenceMode;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.BasicConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 @Catalog(name="MongoDB Server",

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/CoLocatedMongoDBRouter.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/CoLocatedMongoDBRouter.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/CoLocatedMongoDBRouter.java
index 490455c..55bad2e 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/CoLocatedMongoDBRouter.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/CoLocatedMongoDBRouter.java
@@ -26,8 +26,8 @@ import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.software.base.SameServerEntity;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 import com.google.common.reflect.TypeToken;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/CoLocatedMongoDBRouterImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/CoLocatedMongoDBRouterImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/CoLocatedMongoDBRouterImpl.java
index d468f60..e27cb4b 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/CoLocatedMongoDBRouterImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/CoLocatedMongoDBRouterImpl.java
@@ -24,8 +24,8 @@ import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.entity.software.base.SameServerEntityImpl;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
 
 import com.google.common.base.Predicates;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBConfigServerCluster.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBConfigServerCluster.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBConfigServerCluster.java
index 0c102ac..73ac77d 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBConfigServerCluster.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBConfigServerCluster.java
@@ -20,8 +20,8 @@ package org.apache.brooklyn.entity.nosql.mongodb.sharding;
 
 import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.sensor.core.Sensors;
 
 import com.google.common.reflect.TypeToken;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBRouter.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBRouter.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBRouter.java
index 840925b..9191391 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBRouter.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBRouter.java
@@ -23,8 +23,8 @@ import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.nosql.mongodb.AbstractMongoDBServer;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.time.Duration;
 
 import com.google.common.reflect.TypeToken;



[31/36] incubator-brooklyn git commit: Rename o.a.b.sensor.enricher to o.a.b.core.enricher

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricher.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricher.java
deleted file mode 100644
index 51d3d48..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricher.java
+++ /dev/null
@@ -1,180 +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.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-
-/** 
- * an enricher policy which just listens for the target sensor(s) on a child entity and passes it up.
- * now superseded by syntax such as:
- * 
- * <pre>{@code Enrichers.builder().propagating(XXX).from(source).build()}</pre>
- * 
- * @deprecated since 0.7.0; use {@link Enrichers#builder()}
- * 
- * @see Propagator if need to sub-class
- */
-public class SensorPropagatingEnricher extends AbstractEnricher implements SensorEventListener<Object> {
-    
-    public static final Logger log = LoggerFactory.getLogger(SensorPropagatingEnricher.class);
-        
-    /** the entity to listen to */
-    private final Entity source;
-    
-    /** the sensors to listen to */
-    private final Set<Sensor<?>> sensors;
-
-    /** the sensors to listen to */
-    private final Map<Sensor<?>, Sensor<?>> sensorMappings;
-
-    public static SensorPropagatingEnricher newInstanceListeningToAllSensors(Entity source) {
-        return newInstanceListeningToAllSensorsBut(source);
-    }
-    public static SensorPropagatingEnricher newInstanceListeningToAllSensorsBut(Entity source, Sensor<?>... excludes) {
-        Set<Sensor<?>> excluded = ImmutableSet.copyOf(excludes);
-        Set<Sensor<?>> includes = Sets.newLinkedHashSet();
-        
-        for (Sensor<?> it : source.getEntityType().getSensors()) {
-            if (!excluded.contains(it)) includes.add(it);
-        }
-        return new SensorPropagatingEnricher(source, includes);
-    }
-
-    public static SensorPropagatingEnricher newInstanceListeningTo(Entity source, Sensor<?>... includes) {
-        return new SensorPropagatingEnricher(source, includes);
-    }
-
-    /**
-     * listens to sensors from source, propagates them here renamed according to the map
-     * 
-     * Instead, consider calling:
-     * <pre>
-     * {@code
-     * addEnricher(Enrichers.builder()
-     *         .propagating(mapOfOldSensorNamesToNewSensorNames)
-     *         .from(source)
-     *         .build());
-     * }
-     * </pre>
-     *
-     * @deprecated since 0.7.0; use {@link Enrichers#builder()}
-     */
-    public static SensorPropagatingEnricher newInstanceRenaming(Entity source, Map<? extends Sensor<?>, ? extends Sensor<?>> sensors) {
-        return new SensorPropagatingEnricher(source, sensors);
-    }
-
-    /**
-     * @deprecated since 0.7.0; use {@link Enrichers#builder()}
-     */
-    public SensorPropagatingEnricher(Entity source, Sensor<?>... sensors) {
-        this(source, ImmutableList.copyOf(sensors));
-    }
-    
-    /** 
-     * Instead, consider calling:
-     * <pre>
-     * {@code
-     * addEnricher(Enrichers.builder()
-     *         .propagating(sensors)
-     *         .from(source)
-     *         .build());
-     * }
-     * </pre>
-     *
-     * @deprecated since 0.7.0; use {@link Enrichers#builder()}
-     */
-    public SensorPropagatingEnricher(Entity source, Collection<Sensor<?>> sensors) {
-        this.source = source;
-        this.sensors = ImmutableSet.copyOf(sensors);
-        this.sensorMappings = ImmutableMap.of();
-    }
-    
-    public SensorPropagatingEnricher(Entity source, Map<? extends Sensor<?>, ? extends Sensor<?>> sensors) {
-        this.source = source;
-        this.sensors = ImmutableSet.copyOf(sensors.keySet());
-        this.sensorMappings = ImmutableMap.copyOf(sensors);
-    }
-    
-    public void setEntity(EntityLocal entity) {
-        super.setEntity(entity);
-        for (Sensor<?> s: sensors) {
-            subscribe(source, s, this);
-        }
-    }
-    
-    @Override
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    public void onEvent(SensorEvent<Object> event) {
-        // propagate upwards
-        Sensor<?> sourceSensor = event.getSensor();
-        Sensor<?> destinationSensor = getDestinationSensor(sourceSensor);
-        
-        if (log.isTraceEnabled()) log.trace("policy {} got {}, propagating via {}{}", 
-                new Object[] {this, event, entity, (sourceSensor == destinationSensor ? "" : " (as "+destinationSensor+")")});
-        
-        if (event.getSensor() instanceof AttributeSensor) {
-            entity.setAttribute((AttributeSensor)destinationSensor, event.getValue());
-        } else {
-            entity.emit((Sensor)destinationSensor, event.getValue());
-        }       
-    }
-
-    /** useful post-addition to emit current values */
-    public void emitAllAttributes() {
-        emitAllAttributes(false);
-    }
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    public void emitAllAttributes(boolean includeNullValues) {
-        for (Sensor s: sensors) {
-            if (s instanceof AttributeSensor) {
-                AttributeSensor destinationSensor = (AttributeSensor<?>) getDestinationSensor(s);
-                Object v = source.getAttribute((AttributeSensor)s);
-                if (v != null || includeNullValues) entity.setAttribute(destinationSensor, v);
-            }
-        }
-    }
-
-    /** convenience, to be called by the host */
-    public SensorPropagatingEnricher addToEntityAndEmitAll(Entity host) {
-        host.addEnricher(this);
-        emitAllAttributes();
-        return this;
-    }
-    
-    private Sensor<?> getDestinationSensor(Sensor<?> sourceSensor) {
-        return sensorMappings.containsKey(sourceSensor) ? sensorMappings.get(sourceSensor): sourceSensor;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/SensorTransformingEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/SensorTransformingEnricher.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/SensorTransformingEnricher.java
deleted file mode 100644
index 2ad1bdf..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/SensorTransformingEnricher.java
+++ /dev/null
@@ -1,106 +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.entity.Entity;
-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.util.groovy.GroovyJavaMethods;
-import org.apache.brooklyn.util.javalang.JavaClassNames;
-import org.apache.brooklyn.util.time.Duration;
-
-import groovy.lang.Closure;
-
-import com.google.common.base.Function;
-
-/**
- * @deprecated since 0.7.0; use {@link Enrichers.builder()}
- * @see Transformer if need to sub-class
- */
-public class SensorTransformingEnricher<T,U> extends AbstractTypeTransformingEnricher {
-
-    private Function<? super T, ? extends U> transformation;
-
-    public SensorTransformingEnricher(Entity producer, Sensor<T> source, Sensor<U> target, Function<? super T, ? extends U> transformation) {
-        super(producer, source, target);
-        this.transformation = transformation;
-        this.uniqueTag = JavaClassNames.simpleClassName(getClass())+":"+source.getName()+"*->"+target.getName();;
-    }
-
-    public SensorTransformingEnricher(Entity producer, Sensor<T> source, Sensor<U> target, Closure transformation) {
-        this(producer, source, target, GroovyJavaMethods.functionFromClosure(transformation));
-    }
-
-    public SensorTransformingEnricher(Sensor<T> source, Sensor<U> target, Function<T,U> transformation) {
-        this(null, source, target, transformation);
-    }
-
-    public SensorTransformingEnricher(Sensor<T> source, Sensor<U> target, Closure transformation) {
-        this(null, source, target, GroovyJavaMethods.functionFromClosure(transformation));
-    }
-
-    @Override
-    public void onEvent(SensorEvent event) {
-        if (accept((T)event.getValue())) {
-            if (target instanceof AttributeSensor)
-                entity.setAttribute((AttributeSensor)target, compute((T)event.getValue()));
-            else 
-                entity.emit(target, compute((T)event.getValue()));
-        }
-    }
-
-    protected boolean accept(T value) {
-        return true;
-    }
-
-    protected U compute(T value) {
-        return transformation.apply(value);
-    }
-
-    /** 
-     * creates an enricher which listens to a source (from the producer), 
-     * transforms it and publishes it under the target
-     * 
-     * Instead, consider calling:
-     * <pre>
-     * {@code
-     * addEnricher(Enrichers.builder()
-     *         .transforming(source)
-     *         .publishing(target)
-     *         .from(producer)
-     *         .computing(transformation)
-     *         .build());
-     * }
-     * </pre>
-     * 
-     * @deprecated since 0.7.0; use {@link Enrichers.builder()}
-     */
-    public static <U,V> SensorTransformingEnricher<U,V> newInstanceTransforming(Entity producer, AttributeSensor<U> source,
-            Function<U,V> transformation, AttributeSensor<V> target) {
-        return new SensorTransformingEnricher<U,V>(producer, source, target, transformation);
-    }
-
-    /** as {@link #newInstanceTransforming(Entity, AttributeSensor, Function, AttributeSensor)}
-     * using the same sensor as the source and the target */
-    public static <T> SensorTransformingEnricher<T,T> newInstanceTransforming(Entity producer, AttributeSensor<T> sensor,
-            Function<T,T> transformation) {
-        return newInstanceTransforming(producer, sensor, transformation, sensor);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/Transformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Transformer.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/Transformer.java
deleted file mode 100644
index f77bd8c..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Transformer.java
+++ /dev/null
@@ -1,103 +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 org.apache.brooklyn.api.sensor.SensorEvent;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.util.collections.MutableSet;
-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.Function;
-import com.google.common.reflect.TypeToken;
-
-//@Catalog(name="Transformer", description="Transforms attributes of an entity; see Enrichers.builder().transforming(...)")
-@SuppressWarnings("serial")
-public class Transformer<T,U> extends AbstractTransformer<T,U> {
-
-    @SuppressWarnings("unused")
-    private static final Logger LOG = LoggerFactory.getLogger(Transformer.class);
-
-    // exactly one of these should be supplied to set a value
-    public static ConfigKey<?> TARGET_VALUE = ConfigKeys.newConfigKey(Object.class, "enricher.targetValue");
-    public static ConfigKey<Function<?, ?>> TRANSFORMATION_FROM_VALUE = ConfigKeys.newConfigKey(new TypeToken<Function<?, ?>>() {}, "enricher.transformation");
-    public static ConfigKey<Function<?, ?>> TRANSFORMATION_FROM_EVENT = ConfigKeys.newConfigKey(new TypeToken<Function<?, ?>>() {}, "enricher.transformation.fromevent");
-    
-    public Transformer() {
-    }
-
-    /** returns a function for transformation, for immediate use only (not for caching, as it may change) */
-    @Override
-    @SuppressWarnings("unchecked")
-    protected Function<SensorEvent<T>, U> getTransformation() {
-        MutableSet<Object> suppliers = MutableSet.of();
-        suppliers.addIfNotNull(config().getRaw(TARGET_VALUE).orNull());
-        suppliers.addIfNotNull(config().getRaw(TRANSFORMATION_FROM_EVENT).orNull());
-        suppliers.addIfNotNull(config().getRaw(TRANSFORMATION_FROM_VALUE).orNull());
-        checkArgument(suppliers.size()==1,  
-            "Must set exactly one of: %s, %s, %s", TARGET_VALUE.getName(), TRANSFORMATION_FROM_VALUE.getName(), TRANSFORMATION_FROM_EVENT.getName());
-        
-        Function<?, ?> fromEvent = config().get(TRANSFORMATION_FROM_EVENT);
-        if (fromEvent != null) {  
-            return (Function<SensorEvent<T>, U>) fromEvent;
-        }
-        
-        final Function<T, U> fromValueFn = (Function<T, U>) config().get(TRANSFORMATION_FROM_VALUE);
-        if (fromValueFn != null) {
-            // named class not necessary as result should not be serialized
-            return new Function<SensorEvent<T>, U>() {
-                @Override public U apply(SensorEvent<T> input) {
-                    return fromValueFn.apply(input.getValue());
-                }
-                @Override
-                public String toString() {
-                    return ""+fromValueFn;
-                }
-            };
-        }
-
-        // from target value
-        // named class not necessary as result should not be serialized
-        final Object targetValueRaw = config().getRaw(TARGET_VALUE).orNull();
-        return new Function<SensorEvent<T>, U>() {
-            @Override public U apply(SensorEvent<T> input) {
-                // evaluate immediately, or return null
-                // PRETTY_QUICK/200ms seems a reasonable compromise for tasks which require BG evaluation
-                // but which are non-blocking
-                // TODO better would be to have a mode in which tasks are not permitted to block on
-                // external events; they can submit tasks and block on them (or even better, have a callback architecture);
-                // however that is a non-trivial refactoring
-                return (U) Tasks.resolving(targetValueRaw).as(targetSensor.getType())
-                    .context(entity)
-                    .description("Computing sensor "+targetSensor+" from "+targetValueRaw)
-                    .timeout(ValueResolver.PRETTY_QUICK_WAIT)
-                    .getMaybe().orNull();
-            }
-            public String toString() {
-                return ""+targetValueRaw;
-            }
-        };
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/UpdatingMap.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/UpdatingMap.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/UpdatingMap.java
deleted file mode 100644
index 6ae48a7..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/UpdatingMap.java
+++ /dev/null
@@ -1,158 +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.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.Entities;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.flags.SetFromFlag;
-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.collect.Maps;
-import com.google.common.reflect.TypeToken;
-
-/**
- * Enricher which updates an entry in a sensor map ({@link #TARGET_SENSOR}) 
- * based on the value of another sensor ({@link #SOURCE_SENSOR}.
- * <p>
- * The key used defaults to the name of the source sensor but can be specified with {@link #KEY_IN_TARGET_SENSOR}.
- * The value placed in the map is the result of applying the function in {@link #COMPUTING} to the sensor value,
- * with default behaviour being to remove an entry if <code>null</code> is returned
- * but this can be overriden by setting {@link #REMOVING_IF_RESULT_IS_NULL} false.
- * {@link Entities#REMOVE} and {@link Entities#UNCHANGED} are also respeced as return values for the computation
- * (ignoring generics).
- * Unlike most other enrichers, this defaults to {@link AbstractEnricher#SUPPRESS_DUPLICATES} being true
- *  
- * @author alex
- *
- * @param <S> source sensor type
- * @param <TKey> key type in target sensor map
- * @param <TVal> value type in target sensor map
- */
-@SuppressWarnings("serial")
-public class UpdatingMap<S,TKey,TVal> extends AbstractEnricher implements SensorEventListener<S> {
-
-    private static final Logger LOG = LoggerFactory.getLogger(UpdatingMap.class);
-
-    @SetFromFlag("fromSensor")
-    public static final ConfigKey<Sensor<?>> SOURCE_SENSOR = ConfigKeys.newConfigKey(new TypeToken<Sensor<?>>() {}, "enricher.sourceSensor");
-    @SetFromFlag("targetSensor")
-    public static final ConfigKey<Sensor<?>> TARGET_SENSOR = ConfigKeys.newConfigKey(new TypeToken<Sensor<?>>() {}, "enricher.targetSensor");
-    @SetFromFlag("key")
-    public static final ConfigKey<?> KEY_IN_TARGET_SENSOR = ConfigKeys.newConfigKey(Object.class, "enricher.updatingMap.keyInTargetSensor",
-        "Key to update in the target sensor map, defaulting to the name of the source sensor");
-    @SetFromFlag("computing")
-    public static final ConfigKey<Function<?, ?>> COMPUTING = ConfigKeys.newConfigKey(new TypeToken<Function<?,?>>() {}, "enricher.updatingMap.computing");
-    @SetFromFlag("removingIfResultIsNull")
-    public static final ConfigKey<Boolean> REMOVING_IF_RESULT_IS_NULL = ConfigKeys.newBooleanConfigKey("enricher.updatingMap.removingIfResultIsNull", 
-        "Whether the key in the target map is removed if the result if the computation is null");
-
-    protected AttributeSensor<S> sourceSensor;
-    protected AttributeSensor<Map<TKey,TVal>> targetSensor;
-    protected TKey key;
-    protected Function<S,? extends TVal> computing;
-    protected Boolean removingIfResultIsNull;
-
-    public UpdatingMap() {
-        this(Maps.newLinkedHashMap());
-    }
-
-    public UpdatingMap(Map<Object, Object> flags) {
-        super(flags);
-        // this always suppresses duplicates, but it updates the same map *in place* so the usual suppress duplicates logic should not be applied
-        // TODO clean up so that we have synchronization guarantees and can inspect the item to see whether it has changed
-        suppressDuplicates = false;
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Override
-    public void setEntity(EntityLocal entity) {
-        super.setEntity(entity);
-        this.sourceSensor = (AttributeSensor<S>) getRequiredConfig(SOURCE_SENSOR);
-        this.targetSensor = (AttributeSensor<Map<TKey,TVal>>) getRequiredConfig(TARGET_SENSOR);
-        this.key = (TKey) getConfig(KEY_IN_TARGET_SENSOR);
-        this.computing = (Function) getRequiredConfig(COMPUTING);
-        this.removingIfResultIsNull = getConfig(REMOVING_IF_RESULT_IS_NULL);
-
-        subscribe(entity, sourceSensor, this);
-        onUpdated();
-    }
-    
-    @Override
-    public void onEvent(SensorEvent<S> event) {
-        onUpdated();
-    }
-
-    /**
-     * Called whenever the values for the set of producers changes (e.g. on an event, or on a member added/removed).
-     */
-    @SuppressWarnings("unchecked")
-    protected void onUpdated() {
-        try {
-            Object v = computing.apply(entity.getAttribute(sourceSensor));
-            if (v == null && !Boolean.FALSE.equals(removingIfResultIsNull)) {
-                v = Entities.REMOVE;
-            }
-            if (v == Entities.UNCHANGED) {
-                // nothing
-            } else {
-                // TODO check synchronization
-                TKey key = this.key;
-                if (key==null) key = (TKey) sourceSensor.getName();
-                
-                Map<TKey, TVal> map = entity.getAttribute(targetSensor);
-
-                boolean created = (map==null);
-                if (created) map = MutableMap.of();
-                
-                boolean changed;
-                if (v == Entities.REMOVE) {
-                    changed = map.containsKey(key);
-                    if (changed)
-                        map.remove(key);
-                } else {
-                    TVal oldV = map.get(key);
-                    if (oldV==null)
-                        changed = (v!=null || !map.containsKey(key));
-                    else
-                        changed = !oldV.equals(v);
-                    if (changed)
-                        map.put(key, (TVal)v);
-                }
-                if (changed || created)
-                    emit(targetSensor, map);
-            }
-        } catch (Throwable t) {
-            LOG.warn("Error calculating map update for enricher "+this, t);
-            throw Exceptions.propagate(t);
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/YamlRollingTimeWindowMeanEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/YamlRollingTimeWindowMeanEnricher.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/YamlRollingTimeWindowMeanEnricher.java
deleted file mode 100644
index dc65fa8..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/YamlRollingTimeWindowMeanEnricher.java
+++ /dev/null
@@ -1,178 +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.Iterator;
-import java.util.LinkedList;
-
-import org.apache.brooklyn.api.sensor.Sensor;
-import org.apache.brooklyn.api.sensor.SensorEvent;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.util.time.Duration;
-
-import com.google.common.base.Function;
-
-/**
- * Transforms {@link Sensor} data into a rolling average based on a time window.
- * 
- * All values within the window are weighted or discarded based on the timestamps associated with
- * them (discards occur when a new value is added or an average is requested)
- * <p>
- * This will not extrapolate figures - it is assumed a value is valid and correct for the entire
- * time period between it and the previous value. Normally, the average attribute is only updated
- * when a new value arrives so it can give a fully informed average, but there is a danger of this
- * going stale.
- * <p>
- * When an average is requested, it is likely there will be a segment of the window for which there
- * isn't a value. Instead of extrapolating a value and providing different extrapolation techniques,
- * the average is reported with a confidence value which reflects the fraction of the time
- * window for which the values were valid.
- * <p>
- * Consumers of the average may ignore the confidence value and just use the last known average.
- * They could multiply the returned value by the confidence value to get a decay-type behavior as
- * the window empties. A third alternative is to, at a certain confidence threshold, report that
- * the average is no longer meaningful.
- * <p>
- * The default average when no data has been received is 0, with a confidence of 0
- */
-public class YamlRollingTimeWindowMeanEnricher<T extends Number> extends AbstractTransformer<T,Double> {
-    
-    public static ConfigKey<Duration> WINDOW_DURATION = ConfigKeys.newConfigKey(Duration.class, "enricher.window.duration",
-        "Duration for which this window should store data, default one minute", Duration.ONE_MINUTE);
-
-    public static ConfigKey<Double> CONFIDENCE_REQUIRED_TO_PUBLISH = ConfigKeys.newDoubleConfigKey("enricher.window.confidenceRequired",
-        "Minimum confidence level (ie period covered) required to publish a rolling average", 0.8d);
-
-    public static class ConfidenceQualifiedNumber {
-        final Double value;
-        final double confidence;
-        
-        public ConfidenceQualifiedNumber(Double value, double confidence) {
-            this.value = value;
-            this.confidence = confidence;
-        }
-        
-        @Override
-        public String toString() {
-            return ""+value+" ("+(int)(confidence*100)+"%)";
-        } 
-        
-    }
-    
-    private final LinkedList<T> values = new LinkedList<T>();
-    private final LinkedList<Long> timestamps = new LinkedList<Long>();
-    volatile ConfidenceQualifiedNumber lastAverage = new ConfidenceQualifiedNumber(0d,0d);
-    
-    @Override
-    protected Function<SensorEvent<T>, Double> getTransformation() {
-        return new Function<SensorEvent<T>, Double>() {
-            @Override
-            public Double apply(SensorEvent<T> event) {
-                long eventTime = event.getTimestamp();
-                if (event.getValue()==null) {
-                    return null;
-                }
-                values.addLast(event.getValue());
-                timestamps.addLast(eventTime);
-                if (eventTime>0) {
-                    ConfidenceQualifiedNumber average = getAverage(eventTime, 0);
-
-                    if (average.confidence > getConfig(CONFIDENCE_REQUIRED_TO_PUBLISH)) { 
-                        // without confidence, we might publish wildly varying estimates,
-                        // causing spurious resizes, so allow it to be configured, and
-                        // by default require a high value
-
-                        // TODO would be nice to include timestamp, etc
-                        return average.value; 
-                    }
-                }
-                return null;
-            }
-        };
-    }
-    
-    public ConfidenceQualifiedNumber getAverage(long fromTime, long graceAllowed) {
-        if (timestamps.isEmpty()) {
-            return lastAverage = new ConfidenceQualifiedNumber(lastAverage.value, 0.0d);
-        }
-        
-        long firstTimestamp = -1;
-        Iterator<Long> ti = timestamps.iterator();
-        while (ti.hasNext()) {
-            firstTimestamp = ti.next();
-            if (firstTimestamp>0) break;
-        }
-        if (firstTimestamp<=0) {
-            // no values with reasonable timestamps
-            return lastAverage = new ConfidenceQualifiedNumber(values.get(values.size()-1).doubleValue(), 0.0d);
-        }
-
-        long lastTimestamp = timestamps.get(timestamps.size()-1);
-
-        long now = fromTime;
-        if (lastTimestamp > fromTime - graceAllowed) {
-            // without this, if the computation takes place X seconds after the publish,
-            // we treat X seconds as time for which we have no confidence in the data
-            now = lastTimestamp;
-        }
-        pruneValues(now);
-        
-        Duration timePeriod = getConfig(WINDOW_DURATION);
-        long windowStart = Math.max(now-timePeriod.toMilliseconds(), firstTimestamp);
-        long windowEnd = Math.max(now-timePeriod.toMilliseconds(), lastTimestamp);
-        Double confidence = ((double)(windowEnd - windowStart)) / timePeriod.toMilliseconds();
-        if (confidence <= 0.0000001d) {
-            // not enough timestamps in window 
-            double lastValue = values.get(values.size()-1).doubleValue();
-            return lastAverage = new ConfidenceQualifiedNumber(lastValue, 0.0d);
-        }
-        
-        long start = windowStart;
-        long end;
-        double weightedAverage = 0.0d;
-        
-        Iterator<T> valuesIter = values.iterator();
-        Iterator<Long> timestampsIter = timestamps.iterator();
-        while (valuesIter.hasNext()) {
-            // Ignores null and out-of-date values (and also values that are received out-of-order, but that shouldn't happen!)
-            Number val = valuesIter.next();
-            Long timestamp = timestampsIter.next();
-            if (val!=null && timestamp >= start) {
-                end = timestamp;
-                weightedAverage += ((end - start) / (confidence * timePeriod.toMilliseconds())) * val.doubleValue();
-                start = timestamp;
-            }
-        }
-        
-        return lastAverage = new ConfidenceQualifiedNumber(weightedAverage, confidence);
-    }
-    
-    /**
-     * Discards out-of-date values, but keeps at least one value.
-     */
-    private void pruneValues(long now) {
-        // keep one value from before the period, so that we can tell the window's start time
-        Duration timePeriod = getConfig(WINDOW_DURATION);
-        while(timestamps.size() > 1 && timestamps.get(1) < (now - timePeriod.toMilliseconds())) {
-            timestamps.removeFirst();
-            values.removeFirst();
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/YamlTimeWeightedDeltaEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/YamlTimeWeightedDeltaEnricher.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/YamlTimeWeightedDeltaEnricher.java
deleted file mode 100644
index c49ac26..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/YamlTimeWeightedDeltaEnricher.java
+++ /dev/null
@@ -1,83 +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.SensorEvent;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.sensor.enricher.AbstractTransformer;
-import org.apache.brooklyn.util.core.flags.TypeCoercions;
-import org.apache.brooklyn.util.time.Duration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Function;
-
-/**
- * Converts an absolute count sensor into a delta sensor (i.e. the diff between the current and previous value),
- * presented as a units/timeUnit based on the event timing.
- * <p>
- * For example, given a requests.count sensor, this can make a requests.per_sec sensor with {@link #DELTA_PERIOD} set to "1s" (the default).
- * <p>
- * Suitable for configuration from YAML.
- */
-public class YamlTimeWeightedDeltaEnricher<T extends Number> extends AbstractTransformer<T,Double> {
-    private static final Logger LOG = LoggerFactory.getLogger(YamlTimeWeightedDeltaEnricher.class);
-    
-    transient Object lock = new Object();
-    Number lastValue;
-    long lastTime = -1;
-    
-    public static ConfigKey<Duration> DELTA_PERIOD = ConfigKeys.newConfigKey(Duration.class, "enricher.delta.period",
-        "Duration that this delta should compute for, default per second", Duration.ONE_SECOND);
-    
-    @Override
-    protected Function<SensorEvent<T>, Double> getTransformation() {
-        return new Function<SensorEvent<T>, Double>() {
-            @Override
-            public Double apply(SensorEvent<T> event) {
-                synchronized (lock) {
-                    Double current = TypeCoercions.coerce(event.getValue(), Double.class);
-
-                    if (current == null) return null;
-
-                    long eventTime = event.getTimestamp();
-                    long unitMillis = getConfig(DELTA_PERIOD).toMilliseconds();
-                    Double result = null;
-
-                    if (eventTime > 0 && eventTime > lastTime) {
-                        if (lastValue == null || lastTime < 0) {
-                            // cannot calculate time-based delta with a single value
-                            if (LOG.isTraceEnabled()) LOG.trace("{} received event but no last value so will not emit, null -> {} at {}", new Object[] {this, current, eventTime}); 
-                        } else {
-                            double duration = eventTime - lastTime;
-                            result = (current - lastValue.doubleValue()) / (duration / unitMillis);
-                        }
-                    }
-
-                    lastValue = current;
-                    lastTime = eventTime;
-
-                    return result;
-                }
-            }
-        };
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/core/enricher/BasicEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/enricher/BasicEnricherTest.java b/core/src/test/java/org/apache/brooklyn/core/enricher/BasicEnricherTest.java
new file mode 100644
index 0000000..be87f1f
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/enricher/BasicEnricherTest.java
@@ -0,0 +1,119 @@
+/*
+ * 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.core.enricher;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.sensor.Enricher;
+import org.apache.brooklyn.api.sensor.EnricherSpec;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.BasicConfigKey;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
+import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
+import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.core.test.entity.TestApplicationNoEnrichersImpl;
+import org.apache.brooklyn.util.collections.MutableSet;
+import org.apache.brooklyn.util.core.flags.SetFromFlag;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.Iterables;
+
+/**
+ * Test that enricher can be created and accessed, by construction and by spec
+ */
+public class BasicEnricherTest extends BrooklynAppUnitTestSupport {
+    
+    // TODO These tests are a copy of BasicPolicyTest, which is a code smell.
+    // However, the src/main/java code does not contain as much duplication.
+
+    protected void setUpApp() {
+        EntitySpec<TestApplication> appSpec = EntitySpec.create(TestApplication.class, TestApplicationNoEnrichersImpl.class)
+                .configure(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, shouldSkipOnBoxBaseDirResolution());
+        app = ApplicationBuilder.newManagedApp(appSpec, mgmt);
+    }
+
+    public static class MyEnricher extends AbstractEnricher {
+        @SetFromFlag("intKey")
+        public static final BasicConfigKey<Integer> INT_KEY = new BasicConfigKey<Integer>(Integer.class, "bkey", "b key");
+        
+        @SetFromFlag("strKey")
+        public static final ConfigKey<String> STR_KEY = new BasicConfigKey<String>(String.class, "akey", "a key");
+        public static final ConfigKey<Integer> INT_KEY_WITH_DEFAULT = new BasicConfigKey<Integer>(Integer.class, "ckey", "c key", 1);
+        public static final ConfigKey<String> STR_KEY_WITH_DEFAULT = new BasicConfigKey<String>(String.class, "strKey", "str key", "str key default");
+        
+        MyEnricher(Map<?,?> flags) {
+            super(flags);
+        }
+        
+        public MyEnricher() {
+            super();
+        }
+    }
+    
+    @Test
+    public void testAddInstance() throws Exception {
+        MyEnricher enricher = new MyEnricher();
+        enricher.setDisplayName("Bob");
+        enricher.config().set(MyEnricher.STR_KEY, "aval");
+        enricher.config().set(MyEnricher.INT_KEY, 2);
+        app.addEnricher(enricher);
+        
+        assertEquals(enricher.getDisplayName(), "Bob");
+        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval");
+        assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2);
+    }
+    
+    @Test
+    public void testAddSpec() throws Exception {
+        MyEnricher enricher = app.addEnricher(EnricherSpec.create(MyEnricher.class)
+            .displayName("Bob")
+            .configure(MyEnricher.STR_KEY, "aval").configure(MyEnricher.INT_KEY, 2));
+        
+        assertEquals(enricher.getDisplayName(), "Bob");
+        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval");
+        assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2);
+    }
+        
+    @Test
+    public void testTagsFromSpec() throws Exception {
+        MyEnricher enricher = app.addEnricher(EnricherSpec.create(MyEnricher.class).tag(99).uniqueTag("x"));
+
+        assertEquals(enricher.tags().getTags(), MutableSet.of("x", 99));
+        assertEquals(enricher.getUniqueTag(), "x");
+    }
+
+    @Test
+    public void testSameUniqueTagEnricherNotAddedTwice() throws Exception {
+        app.addEnricher(EnricherSpec.create(MyEnricher.class).tag(99).uniqueTag("x"));
+        app.addEnricher(EnricherSpec.create(MyEnricher.class).tag(94).uniqueTag("x"));
+        
+        assertEquals(app.getEnrichers().size(), 1);
+        // the more recent one should dominate
+        Enricher enricher = Iterables.getOnlyElement(app.getEnrichers());
+        Assert.assertTrue(enricher.tags().containsTag(94));
+        Assert.assertFalse(enricher.tags().containsTag(99));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/core/enricher/EnricherConfigTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/enricher/EnricherConfigTest.java b/core/src/test/java/org/apache/brooklyn/core/enricher/EnricherConfigTest.java
new file mode 100644
index 0000000..150a09b
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/enricher/EnricherConfigTest.java
@@ -0,0 +1,147 @@
+/*
+ * 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.core.enricher;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import org.apache.brooklyn.core.config.BasicConfigKey;
+import org.apache.brooklyn.core.enricher.BasicEnricherTest.MyEnricher;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.testng.annotations.Test;
+
+/**
+ * Test that configuration properties are usable and inherited correctly.
+ */
+public class EnricherConfigTest extends BrooklynAppUnitTestSupport {
+    
+    // TODO These tests are a copy of PolicyConfigTest, which is a code smell.
+    // However, the src/main/java code does not contain as much duplication.
+    
+    private BasicConfigKey<String> differentKey = new BasicConfigKey<String>(String.class, "differentkey", "diffval");
+
+    @Test
+    public void testConfigFlagsPassedInAtConstructionIsAvailable() throws Exception {
+        MyEnricher enricher = new MyEnricher(MutableMap.builder()
+                .put("strKey", "aval")
+                .put("intKey", 2)
+                .build());
+        app.addEnricher(enricher);
+        
+        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval");
+        assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2);
+        // this is set, because key name matches annotation on STR_KEY
+        assertEquals(enricher.getConfig(MyEnricher.STR_KEY_WITH_DEFAULT), "aval");
+    }
+    
+    @Test
+    public void testUnknownConfigPassedInAtConstructionIsWarnedAndIgnored() throws Exception {
+        // TODO Also assert it's warned
+        MyEnricher enricher = new MyEnricher(MutableMap.builder()
+                .put(differentKey, "aval")
+                .build());
+        app.addEnricher(enricher);
+        
+        assertEquals(enricher.getConfig(differentKey), null);
+        assertEquals(enricher.getEnricherType().getConfigKey(differentKey.getName()), null);
+    }
+    
+    @Test
+    public void testConfigPassedInAtConstructionIsAvailable() throws Exception {
+        MyEnricher enricher = new MyEnricher(MutableMap.builder()
+                .put(MyEnricher.STR_KEY, "aval")
+                .put(MyEnricher.INT_KEY, 2)
+                .build());
+        app.addEnricher(enricher);
+        
+        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval");
+        assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2);
+        // this is not set (contrast with above)
+        assertEquals(enricher.getConfig(MyEnricher.STR_KEY_WITH_DEFAULT), MyEnricher.STR_KEY_WITH_DEFAULT.getDefaultValue());
+    }
+    
+    @Test
+    public void testConfigSetToGroovyTruthFalseIsAvailable() throws Exception {
+        MyEnricher enricher = new MyEnricher(MutableMap.builder()
+                .put(MyEnricher.INT_KEY_WITH_DEFAULT, 0)
+                .build());
+        app.addEnricher(enricher);
+        
+        assertEquals(enricher.getConfig(MyEnricher.INT_KEY_WITH_DEFAULT), (Integer)0);
+    }
+    
+    @Test
+    public void testConfigSetToNullIsAvailable() throws Exception {
+        MyEnricher enricher = new MyEnricher(MutableMap.builder()
+                .put(MyEnricher.STR_KEY_WITH_DEFAULT, null)
+                .build());
+        app.addEnricher(enricher);
+        
+        assertEquals(enricher.getConfig(MyEnricher.STR_KEY_WITH_DEFAULT), null);
+    }
+    
+    @Test
+    public void testConfigCanBeSetOnEnricher() throws Exception {
+        MyEnricher enricher = new MyEnricher();
+        enricher.config().set(MyEnricher.STR_KEY, "aval");
+        enricher.config().set(MyEnricher.INT_KEY, 2);
+        app.addEnricher(enricher);
+        
+        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval");
+        assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2);
+    }
+    
+    @Test
+    public void testConfigSetterOverridesConstructorValue() throws Exception {
+        MyEnricher enricher = new MyEnricher(MutableMap.builder()
+                .put(MyEnricher.STR_KEY, "aval")
+                .build());
+        enricher.config().set(MyEnricher.STR_KEY, "diffval");
+        app.addEnricher(enricher);
+        
+        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "diffval");
+    }
+
+    @Test
+    public void testConfigCannotBeSetAfterApplicationIsStarted() throws Exception {
+        MyEnricher enricher = new MyEnricher(MutableMap.builder()
+                .put(MyEnricher.STR_KEY, "origval")
+                .build());
+        app.addEnricher(enricher);
+        
+        try {
+            enricher.config().set(MyEnricher.STR_KEY,"newval");
+            fail();
+        } catch (UnsupportedOperationException e) {
+            // success
+        }
+        
+        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "origval");
+    }
+    
+    @Test
+    public void testConfigReturnsDefaultValueIfNotSet() throws Exception {
+        MyEnricher enricher = new MyEnricher();
+        app.addEnricher(enricher);
+        
+        assertEquals(enricher.getConfig(MyEnricher.STR_KEY_WITH_DEFAULT), "str key default");
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/core/entity/EntitySpecTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/EntitySpecTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/EntitySpecTest.java
index d53bc87..1fec2e8 100644
--- a/core/src/test/java/org/apache/brooklyn/core/entity/EntitySpecTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/EntitySpecTest.java
@@ -30,6 +30,7 @@ import org.apache.brooklyn.api.sensor.EnricherSpec;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.BasicConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
 import org.apache.brooklyn.core.location.SimulatedLocation;
 import org.apache.brooklyn.core.policy.AbstractPolicy;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
@@ -37,7 +38,6 @@ import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.core.test.entity.TestEntityImpl;
 import org.apache.brooklyn.core.test.entity.TestEntityNoEnrichersImpl;
 import org.apache.brooklyn.entity.group.BasicGroup;
-import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.testng.annotations.BeforeMethod;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterTestFixture.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterTestFixture.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterTestFixture.java
index f751bcb..03a9c79 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterTestFixture.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterTestFixture.java
@@ -46,7 +46,7 @@ import org.apache.brooklyn.core.mgmt.rebind.RecordingRebindExceptionHandler;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.core.test.policy.TestPolicy;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.testng.SkipException;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEnricherTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEnricherTest.java
index c4d295a..e79ba8a 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEnricherTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEnricherTest.java
@@ -34,6 +34,7 @@ import org.apache.brooklyn.api.sensor.Enricher;
 import org.apache.brooklyn.api.sensor.EnricherSpec;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.EntityPredicates;
@@ -42,9 +43,8 @@ import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.core.test.entity.TestEntityImpl;
+import org.apache.brooklyn.enricher.stock.Enrichers;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.collections.MutableSet;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFailuresTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFailuresTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFailuresTest.java
index 26ee74f..e78f062 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFailuresTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFailuresTest.java
@@ -42,6 +42,7 @@ import org.apache.brooklyn.api.sensor.EnricherSpec;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.config.ConfigMap;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
 import org.apache.brooklyn.core.entity.EntityFunctions;
 import org.apache.brooklyn.core.entity.EntityPredicates;
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
@@ -49,7 +50,6 @@ import org.apache.brooklyn.core.mgmt.rebind.RebindEntityTest.MyEntity;
 import org.apache.brooklyn.core.mgmt.rebind.RebindEntityTest.MyEntityImpl;
 import org.apache.brooklyn.core.policy.AbstractPolicy;
 import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
-import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.os.Os;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindPolicyTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindPolicyTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindPolicyTest.java
index 28c9ba8..faff0c9 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindPolicyTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindPolicyTest.java
@@ -35,6 +35,7 @@ import org.apache.brooklyn.api.policy.PolicySpec;
 import org.apache.brooklyn.api.sensor.EnricherSpec;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.Locations;
 import org.apache.brooklyn.core.mgmt.rebind.RebindEnricherTest.MyEnricher;
@@ -42,7 +43,6 @@ import org.apache.brooklyn.core.policy.AbstractPolicy;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.entity.group.BasicGroup;
-import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/core/policy/basic/EnricherTypeTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/policy/basic/EnricherTypeTest.java b/core/src/test/java/org/apache/brooklyn/core/policy/basic/EnricherTypeTest.java
index a9f9655..12a6bff 100644
--- a/core/src/test/java/org/apache/brooklyn/core/policy/basic/EnricherTypeTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/policy/basic/EnricherTypeTest.java
@@ -22,7 +22,7 @@ import static org.testng.Assert.assertEquals;
 
 import org.apache.brooklyn.api.sensor.EnricherType;
 import org.apache.brooklyn.core.config.BasicConfigKey;
-import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/core/test/policy/TestEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/test/policy/TestEnricher.java b/core/src/test/java/org/apache/brooklyn/core/test/policy/TestEnricher.java
index 2340c51..42b52d2 100644
--- a/core/src/test/java/org/apache/brooklyn/core/test/policy/TestEnricher.java
+++ b/core/src/test/java/org/apache/brooklyn/core/test/policy/TestEnricher.java
@@ -26,7 +26,7 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.BasicConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 import com.google.common.reflect.TypeToken;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/enricher/stock/CustomAggregatingEnricherDeprecatedTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/enricher/stock/CustomAggregatingEnricherDeprecatedTest.groovy b/core/src/test/java/org/apache/brooklyn/enricher/stock/CustomAggregatingEnricherDeprecatedTest.groovy
new file mode 100644
index 0000000..481e233
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/enricher/stock/CustomAggregatingEnricherDeprecatedTest.groovy
@@ -0,0 +1,368 @@
+/*
+ * 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.enricher.stock
+
+import static org.testng.Assert.assertEquals
+
+import org.apache.brooklyn.api.entity.EntitySpec
+import org.apache.brooklyn.api.sensor.AttributeSensor
+import org.apache.brooklyn.core.test.entity.TestApplication
+import org.apache.brooklyn.core.test.entity.TestEntity
+import org.apache.brooklyn.enricher.stock.CustomAggregatingEnricher;
+import org.apache.brooklyn.core.entity.Entities
+import org.apache.brooklyn.entity.group.BasicGroup
+import org.apache.brooklyn.core.location.SimulatedLocation
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor
+import org.apache.brooklyn.test.TestUtils
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+import org.testng.annotations.AfterMethod
+import org.testng.annotations.BeforeMethod
+import org.testng.annotations.Test
+
+import com.google.common.base.Function
+
+class CustomAggregatingEnricherDeprecatedTest {
+
+    public static final Logger log = LoggerFactory.getLogger(CustomAggregatingEnricherDeprecatedTest.class);
+            
+    private static final long TIMEOUT_MS = 10*1000
+    private static final long SHORT_WAIT_MS = 250
+    
+    TestApplication app
+    TestEntity producer
+    
+    AttributeSensor<Integer> intSensor
+    AttributeSensor<Integer> target
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() {
+        app = TestApplication.Factory.newManagedInstanceForTests();
+        producer = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        intSensor = new BasicAttributeSensor<Integer>(Integer.class, "int sensor")
+        target = new BasicAttributeSensor<Integer>(Long.class, "target sensor")
+        
+        app.start([new SimulatedLocation()])
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() {
+        if (app!=null) Entities.destroyAll(app.getManagementContext());
+    }
+    
+    @Test
+    public void testEnrichersWithNoProducers() {
+        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher([:], intSensor, target, 11, 40)
+        producer.addEnricher(cae)
+        assertEquals cae.getAggregate(), 40
+    }
+
+    @Test
+    public void testSummingEnricherWhenNoSensorValuesYet() {
+        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(
+                intSensor, target, producers:[producer], 11, 40)
+        producer.addEnricher(cae)
+        assertEquals cae.getAggregate(), 11
+    }
+
+    @Test
+    public void testSingleProducerSum() {
+        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(
+                intSensor, target, null, null, producers:[producer])
+        producer.addEnricher(cae)
+        assertEquals cae.getAggregate(), null
+        cae.onEvent(intSensor.newEvent(producer, 1))
+        assertEquals cae.getAggregate(), 1
+    }
+    
+    @Test
+    public void testSummingEnricherWhenNoAndNullSensorValue() {
+        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(
+                intSensor, target, null, null, producers:[producer])
+        producer.addEnricher(cae)
+        assertEquals cae.getAggregate(), null
+        cae.onEvent(intSensor.newEvent(producer, null))
+        assertEquals cae.getAggregate(), null
+    }
+    
+    @Test
+    public void testSummingEnricherWhenNoAndNullSensorValueExplicitValue() {
+        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(
+                intSensor, target, 3 /** if null */, 5 /** if none */, producers:[producer])
+        producer.addEnricher(cae)
+        assertEquals cae.getAggregate(), 3
+        cae.onEvent(intSensor.newEvent(producer, null))
+        assertEquals cae.getAggregate(), 3
+        cae.onEvent(intSensor.newEvent(producer, 1))
+        assertEquals cae.getAggregate(), 1
+        cae.onEvent(intSensor.newEvent(producer, 7))
+        assertEquals cae.getAggregate(), 7
+    }
+    
+    @Test
+    public void testMultipleProducersSum() {
+        List<TestEntity> producers = [
+                app.createAndManageChild(EntitySpec.create(TestEntity.class)), 
+                app.createAndManageChild(EntitySpec.create(TestEntity.class)),
+                app.createAndManageChild(EntitySpec.create(TestEntity.class))
+                ]
+        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(
+            intSensor, target, null, null, producers:producers)
+        
+        producer.addEnricher(cae)
+        assertEquals cae.getAggregate(), null
+        cae.onEvent(intSensor.newEvent(producers[2], 1))
+        assertEquals cae.getAggregate(), 1
+        cae.onEvent(intSensor.newEvent(producers[0], 3))
+        assertEquals cae.getAggregate(), 4
+        cae.onEvent(intSensor.newEvent(producers[1], 3))
+        assertEquals cae.getAggregate(), 7
+
+    }
+    
+    @Test
+    public void testAveragingEnricherWhenNoAndNullSensorValues() {
+        List<TestEntity> producers = [ 
+                app.createAndManageChild(EntitySpec.create(TestEntity.class))
+                ]
+        CustomAggregatingEnricher<Double> cae = CustomAggregatingEnricher.<Double>newAveragingEnricher(
+                intSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), null, null, producers:producers)
+        producer.addEnricher(cae)
+        assertEquals cae.getAggregate(), null
+        cae.onEvent(intSensor.newEvent(producers[0], null))
+        assertEquals cae.getAggregate(), null
+    }
+
+    @Test
+    public void testAveragingEnricherWhenNoAndNullSensorValuesExplicit() {
+        List<TestEntity> producers = [
+                app.createAndManageChild(EntitySpec.create(TestEntity.class))
+                ]
+        CustomAggregatingEnricher<Double> cae = CustomAggregatingEnricher.<Double>newAveragingEnricher(
+                intSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), 3 /** if null */, 5 /** if none */,
+                producers:producers)
+        producer.addEnricher(cae)
+        
+        assertEquals cae.getAggregate(), 3d
+        cae.onEvent(intSensor.newEvent(producers[0], null))
+        assertEquals cae.getAggregate(), 3d
+        cae.onEvent(intSensor.newEvent(producers[0], 4))
+        assertEquals cae.getAggregate(), 4d
+    }
+
+    @Test
+    public void testAveragingEnricherWhenNoSensors() {
+        List<TestEntity> producers = [
+                ]
+        CustomAggregatingEnricher<Double> cae = CustomAggregatingEnricher.<Double>newAveragingEnricher(
+                intSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), 3 /** if null */, 5 /** if none */,
+                producers:producers)
+        producer.addEnricher(cae)
+        
+        assertEquals cae.getAggregate(), 5d
+    }
+
+    @Test
+    public void testMultipleProducersAverage() {
+        List<TestEntity> producers = [
+                app.createAndManageChild(EntitySpec.create(TestEntity.class)), 
+                app.createAndManageChild(EntitySpec.create(TestEntity.class)),
+                app.createAndManageChild(EntitySpec.create(TestEntity.class))
+                ]
+        CustomAggregatingEnricher<Double> cae = CustomAggregatingEnricher.<Double>newAveragingEnricher(
+                intSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), null, null, producers:producers)
+        
+        producer.addEnricher(cae)
+        
+        assertEquals cae.getAggregate(), null
+        cae.onEvent(intSensor.newEvent(producers[0], 3))
+        assertEquals cae.getAggregate(), 3d
+        
+        cae.onEvent(intSensor.newEvent(producers[1], 3))
+        assertEquals cae.getAggregate(), 3d
+        
+        cae.onEvent(intSensor.newEvent(producers[2], 6))
+        assertEquals cae.getAggregate(), 4d
+
+        // change p2's value to 7.5, average increase of 0.5.
+        cae.onEvent(intSensor.newEvent(producers[2], 7.5))
+        assertEquals cae.getAggregate(), 4.5d
+    }
+    
+    @Test
+    public void testMultipleProducersAverageDefaultingZero() {
+        List<TestEntity> producers = [
+                app.createAndManageChild(EntitySpec.create(TestEntity.class)), 
+                app.createAndManageChild(EntitySpec.create(TestEntity.class)),
+                app.createAndManageChild(EntitySpec.create(TestEntity.class))
+                ]
+        CustomAggregatingEnricher<Double> cae = CustomAggregatingEnricher.<Double>newAveragingEnricher(
+                intSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), 0, 0, producers:producers)
+        
+        producer.addEnricher(cae)
+        
+        assertEquals cae.getAggregate(), 0d
+        cae.onEvent(intSensor.newEvent(producers[0], 3))
+        assertEquals cae.getAggregate(), 1d
+        
+        cae.onEvent(intSensor.newEvent(producers[1], 3))
+        assertEquals cae.getAggregate(), 2d
+        
+        cae.onEvent(intSensor.newEvent(producers[2], 6))
+        assertEquals cae.getAggregate(), 4d
+
+        // change p2's value to 7.5, average increase of 0.5.
+        cae.onEvent(intSensor.newEvent(producers[2], 7.5))
+        assertEquals cae.getAggregate(), 4.5d
+    }
+    
+    @Test
+    public void testAddingAndRemovingProducers() {
+        TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class)); 
+        TestEntity p2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        
+        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(
+                intSensor, target, null, null, producers:[p1])
+
+        producer.addEnricher(cae)
+        assertEquals cae.getAggregate(), null
+        
+        // Event by initial producer
+        cae.onEvent(intSensor.newEvent(p1, 1))
+        assertEquals cae.getAggregate(), 1
+        
+        // Add producer and fire event
+        cae.addProducer(p2)
+        cae.onEvent(intSensor.newEvent(p2, 4))
+        assertEquals cae.getAggregate(), 5
+        
+        cae.removeProducer(p2)
+        assertEquals cae.getAggregate(), 1
+    }
+    
+    @Test
+    public void testAggregatesNewMembersOfGroup() {
+        try {
+            BasicGroup group = app.createAndManageChild(EntitySpec.create(BasicGroup.class));
+            TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class))
+            TestEntity p2 = app.createAndManageChild(EntitySpec.create(TestEntity.class))
+            log.debug("created $group and the entities it will contain $p1 $p2")
+
+            CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(intSensor, target, 0, 0, allMembers:true)
+            group.addEnricher(cae)
+
+            assertEquals cae.getAggregate(), 0
+
+            group.addMember(p1)
+            p1.setAttribute(intSensor, 1)
+            TestUtils.executeUntilSucceeds(timeout:TIMEOUT_MS) {
+                assertEquals cae.getAggregate(), 1
+            }
+
+            group.addMember(p2)
+            p2.setAttribute(intSensor, 2)
+            TestUtils.executeUntilSucceeds(timeout:TIMEOUT_MS) {
+                assertEquals cae.getAggregate(), 3
+            }
+
+            group.removeMember(p2)
+            TestUtils.executeUntilSucceeds(timeout:TIMEOUT_MS) {
+                assertEquals cae.getAggregate(), 1
+            }
+        } catch (Exception e) {
+            log.error("testAggregatesNewMembersOfGroup failed (now cleaning up): "+e)
+            throw e;
+        }
+    }
+    
+    @Test(groups = "Integration")
+    public void testAggregatesGroupMembersFiftyTimes() {
+        for (int i=0; i<50; i++) {
+            log.debug "testAggregatesNewMembersOfGroup $i"
+            testAggregatesNewMembersOfGroup();
+        }
+    }
+    
+    @Test
+    public void testAggregatesExistingMembersOfGroup() {
+        BasicGroup group = app.addChild(EntitySpec.create(BasicGroup.class));
+        TestEntity p1 = app.getManagementContext().getEntityManager().createEntity(EntitySpec.create(TestEntity.class).parent(group)); 
+        TestEntity p2 = app.getManagementContext().getEntityManager().createEntity(EntitySpec.create(TestEntity.class).parent(group)); 
+        group.addMember(p1)
+        group.addMember(p2)
+        p1.setAttribute(intSensor, 1)
+        Entities.manage(group);
+        
+        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(intSensor, target, null, null, allMembers:true)
+        group.addEnricher(cae)
+        
+        assertEquals cae.getAggregate(), 1
+
+        p2.setAttribute(intSensor, 2)
+        TestUtils.executeUntilSucceeds(timeout:TIMEOUT_MS) {
+            assertEquals cae.getAggregate(), 3
+        }
+        
+        group.removeMember(p2)
+        TestUtils.executeUntilSucceeds(timeout:TIMEOUT_MS) {
+            assertEquals cae.getAggregate(), 1
+        }
+    }
+    
+    @Test
+    public void testAppliesFilterWhenAggregatingMembersOfGroup() {
+        BasicGroup group = app.createAndManageChild(EntitySpec.create(BasicGroup.class));
+        TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        TestEntity p2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        TestEntity p3 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        group.addMember(p1)
+        group.addMember(p2)
+        p1.setAttribute(intSensor, 1)
+        p2.setAttribute(intSensor, 2)
+        p3.setAttribute(intSensor, 4)
+        
+        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(intSensor, target, null, null, allMembers:true, filter:{it == p1})
+        group.addEnricher(cae)
+        
+        assertEquals cae.getAggregate(), 1
+        
+        group.addMember(p3)
+        TestUtils.assertSucceedsContinually(timeout:SHORT_WAIT_MS) {
+            assertEquals cae.getAggregate(), 1
+        }
+    }
+    
+    @Test
+    public void testCustomAggregatingFunction() {
+        TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class)); 
+        Function<Collection<Integer>,Integer> aggregator = { Collection c -> 
+            int result = 0; c.each { result += it*it }; return result;
+        } as Function
+         
+        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newEnricher(
+                intSensor, target, aggregator, 0, producers:[p1])
+
+        producer.addEnricher(cae)
+        assertEquals cae.getAggregate(), 0
+        
+        // Event by producer
+        cae.onEvent(intSensor.newEvent(p1, 2))
+        assertEquals cae.getAggregate(), 4
+    }
+}


[04/36] incubator-brooklyn git commit: Rename o.a.b.effector.core to o.a.b.core.effector

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandEffector.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandEffector.java b/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandEffector.java
index da4a9ce..9e3d885 100644
--- a/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandEffector.java
+++ b/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandEffector.java
@@ -24,12 +24,12 @@ import org.apache.brooklyn.api.effector.Effector;
 import org.apache.brooklyn.api.effector.ParameterType;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.effector.core.AddEffector;
-import org.apache.brooklyn.effector.core.EffectorBody;
-import org.apache.brooklyn.effector.core.Effectors;
-import org.apache.brooklyn.effector.core.Effectors.EffectorBuilder;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks.SshEffectorTaskFactory;
+import org.apache.brooklyn.core.effector.AddEffector;
+import org.apache.brooklyn.core.effector.EffectorBody;
+import org.apache.brooklyn.core.effector.Effectors;
+import org.apache.brooklyn.core.effector.Effectors.EffectorBuilder;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks.SshEffectorTaskFactory;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.config.ConfigBag;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandSensor.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandSensor.java b/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandSensor.java
index 8e28299..c3dd177 100644
--- a/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandSensor.java
+++ b/software/base/src/main/java/org/apache/brooklyn/sensor/ssh/SshCommandSensor.java
@@ -24,7 +24,7 @@ import org.apache.brooklyn.api.entity.EntityInitializer;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.effector.core.AddSensor;
+import org.apache.brooklyn.core.effector.AddSensor;
 import org.apache.brooklyn.entity.java.JmxAttributeSensor;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.sensor.core.HttpRequestSensor;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/SelectMasterEffectorTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/SelectMasterEffectorTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/SelectMasterEffectorTest.java
index b9847ae..ff8884b 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/SelectMasterEffectorTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/SelectMasterEffectorTest.java
@@ -32,9 +32,9 @@ import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.entity.Group;
 import org.apache.brooklyn.api.mgmt.ha.ManagementNodeState;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynCluster;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynClusterImpl;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverMySqlEntityLiveTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverMySqlEntityLiveTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverMySqlEntityLiveTest.java
index 8de4bb0..a0bfba2 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverMySqlEntityLiveTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverMySqlEntityLiveTest.java
@@ -20,8 +20,8 @@ package org.apache.brooklyn.entity.chef.mysql;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
 import org.testng.annotations.Test;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverToyMySqlEntity.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverToyMySqlEntity.java b/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverToyMySqlEntity.java
index 21d1d2f..7d3c895 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverToyMySqlEntity.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/chef/mysql/ChefSoloDriverToyMySqlEntity.java
@@ -22,7 +22,7 @@ import org.apache.brooklyn.api.mgmt.TaskAdaptable;
 import org.apache.brooklyn.api.mgmt.TaskFactory;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.chef.ChefConfig;
 import org.apache.brooklyn.entity.chef.ChefConfigs;
 import org.apache.brooklyn.entity.chef.ChefSoloDriver;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareEffectorTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareEffectorTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareEffectorTest.java
index 244adf8..69d1cfc 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareEffectorTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareEffectorTest.java
@@ -24,11 +24,11 @@ import org.apache.brooklyn.api.effector.Effector;
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.effector.Effectors;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks.SshEffectorBody;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.apache.brooklyn.effector.core.Effectors;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks.SshEffectorBody;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessEntityTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessEntityTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessEntityTest.java
index 0b738aa..0b1515b 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessEntityTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessEntityTest.java
@@ -42,6 +42,7 @@ import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.api.mgmt.TaskAdaptable;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
 import org.apache.brooklyn.core.entity.Entities;
@@ -55,7 +56,6 @@ import org.apache.brooklyn.core.location.Locations;
 import org.apache.brooklyn.core.location.SimulatedLocation;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.entity.software.base.AbstractSoftwareProcessSshDriver;
 import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess;
 import org.apache.brooklyn.entity.software.base.EmptySoftwareProcessDriver;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessSubclassTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessSubclassTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessSubclassTest.java
index 338b1f3..29229ea 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessSubclassTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessSubclassTest.java
@@ -26,9 +26,9 @@ import java.util.List;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.effector.EffectorAndBody;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.effector.core.EffectorAndBody;
-import org.apache.brooklyn.effector.core.MethodEffector;
 import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess;
 import org.apache.brooklyn.entity.software.base.EmptySoftwareProcessImpl;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/mysql/AbstractToyMySqlEntityTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/mysql/AbstractToyMySqlEntityTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/mysql/AbstractToyMySqlEntityTest.java
index 82fd74f..8283637 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/mysql/AbstractToyMySqlEntityTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/mysql/AbstractToyMySqlEntityTest.java
@@ -21,11 +21,11 @@ package org.apache.brooklyn.entity.software.base.test.mysql;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/mysql/DynamicToyMySqlEntityBuilder.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/mysql/DynamicToyMySqlEntityBuilder.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/mysql/DynamicToyMySqlEntityBuilder.java
index 22a8d8d..65baf9a 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/mysql/DynamicToyMySqlEntityBuilder.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/mysql/DynamicToyMySqlEntityBuilder.java
@@ -26,10 +26,10 @@ import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.api.location.OsDetails;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.location.BasicOsDetails.OsVersions;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks;
 import org.apache.brooklyn.entity.stock.BasicStartable;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/ssh/SshCommandIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/ssh/SshCommandIntegrationTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/ssh/SshCommandIntegrationTest.java
index 858576d..8f7b6bf 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/ssh/SshCommandIntegrationTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/ssh/SshCommandIntegrationTest.java
@@ -27,11 +27,11 @@ import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.ssh.SshCommandEffector;
 import org.apache.brooklyn.sensor.ssh.SshCommandSensor;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/base/src/test/java/org/apache/brooklyn/entity/system_service/SystemServiceEnricherTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/system_service/SystemServiceEnricherTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/system_service/SystemServiceEnricherTest.java
index f08cd95..10e2e15 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/system_service/SystemServiceEnricherTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/system_service/SystemServiceEnricherTest.java
@@ -22,12 +22,12 @@ import static org.testng.Assert.assertEquals;
 
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.sensor.EnricherSpec;
+import org.apache.brooklyn.core.effector.EffectorTasks;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityPredicates;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport;
-import org.apache.brooklyn.effector.core.EffectorTasks;
 import org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess;
 import org.apache.brooklyn.entity.software.base.VanillaSoftwareProcessImpl;
 import org.apache.brooklyn.entity.software.base.VanillaSoftwareProcessSshDriver;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/database/src/main/java/org/apache/brooklyn/entity/database/DatastoreMixins.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/DatastoreMixins.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/DatastoreMixins.java
index 5536366..c2acfab 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/DatastoreMixins.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/DatastoreMixins.java
@@ -27,7 +27,7 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.effector.core.Effectors;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java
index 1c803c2..3d8c982 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java
@@ -20,8 +20,8 @@ package org.apache.brooklyn.entity.database.mariadb;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.apache.brooklyn.core.effector.EffectorBody;
 import org.apache.brooklyn.core.location.Locations;
-import org.apache.brooklyn.effector.core.EffectorBody;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.sensor.feed.ssh.SshFeed;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbSshDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbSshDriver.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbSshDriver.java
index 81b4834..c7a4936 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbSshDriver.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbSshDriver.java
@@ -36,9 +36,9 @@ import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.entity.database.DatastoreMixins;
 import org.apache.brooklyn.entity.software.base.AbstractSoftwareProcessSshDriver;
 import org.apache.brooklyn.api.location.OsDetails;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.task.DynamicTasks;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNode.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNode.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNode.java
index 79a12b8..aa11eb4 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNode.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNode.java
@@ -27,9 +27,9 @@ import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.annotation.EffectorParam;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.config.MapConfigKey;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.location.PortRanges;
-import org.apache.brooklyn.effector.core.MethodEffector;
 import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNodeImpl.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNodeImpl.java
index f8f620f..71c73c6 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNodeImpl.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNodeImpl.java
@@ -21,8 +21,8 @@ package org.apache.brooklyn.entity.database.mysql;
 import java.util.Map;
 
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.effector.EffectorBody;
 import org.apache.brooklyn.core.location.Locations;
-import org.apache.brooklyn.effector.core.EffectorBody;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlSshDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlSshDriver.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlSshDriver.java
index 95f497d..313a583 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlSshDriver.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlSshDriver.java
@@ -38,10 +38,10 @@ import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.entity.database.DatastoreMixins;
 import org.apache.brooklyn.entity.software.base.AbstractSoftwareProcessSshDriver;
 import org.apache.brooklyn.api.location.OsDetails;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.BasicOsDetails.OsVersions;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.task.DynamicTasks;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNode.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNode.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNode.java
index 04e3c83..6cb9cde 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNode.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNode.java
@@ -24,8 +24,8 @@ import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.objs.HasShortName;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.location.PortRanges;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.entity.database.DatabaseNode;
 import org.apache.brooklyn.entity.database.DatastoreMixins;
 import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java
index e557090..01fde1f 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java
@@ -21,11 +21,11 @@ package org.apache.brooklyn.entity.database.postgresql;
 import org.apache.brooklyn.api.effector.Effector;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.EffectorBody;
+import org.apache.brooklyn.core.effector.Effectors;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.Locations;
-import org.apache.brooklyn.effector.core.EffectorBody;
-import org.apache.brooklyn.effector.core.Effectors;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.chef.ChefConfig;
 import org.apache.brooklyn.entity.chef.ChefLifecycleEffectorTasks;
 import org.apache.brooklyn.entity.chef.ChefServerTasks;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeImpl.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeImpl.java
index 15d280e..60a53c2 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeImpl.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeImpl.java
@@ -18,7 +18,7 @@
  */
 package org.apache.brooklyn.entity.database.postgresql;
 
-import org.apache.brooklyn.effector.core.EffectorBody;
+import org.apache.brooklyn.core.effector.EffectorBody;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
index cbb289b..f9e80f7 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
@@ -39,8 +39,8 @@ import java.io.InputStream;
 import javax.annotation.Nullable;
 
 import org.apache.brooklyn.api.location.OsDetails;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Attributes;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.collections.MutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlChefTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlChefTest.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlChefTest.java
index bd9ec6b..6f1d014 100644
--- a/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlChefTest.java
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlChefTest.java
@@ -24,12 +24,12 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.Assert;
 import org.testng.annotations.Test;
-import org.apache.brooklyn.effector.core.EffectorTasks;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.chef.ChefLiveTestSupport;
 import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
 import org.apache.brooklyn.entity.database.VogellaExampleAccess;
 import org.apache.brooklyn.api.location.PortRange;
+import org.apache.brooklyn.core.effector.EffectorTasks;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.PortRanges;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenter.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenter.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenter.java
index 66263f5..2f92c47 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenter.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenter.java
@@ -29,8 +29,8 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.effector.core.Effectors;
-import org.apache.brooklyn.effector.core.MethodEffector;
+import org.apache.brooklyn.core.effector.Effectors;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.entity.nosql.cassandra.TokenGenerators.PosNeg63TokenGenerator;
 import org.apache.brooklyn.entity.database.DatastoreMixins;
 import org.apache.brooklyn.entity.group.DynamicCluster;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenterImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenterImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenterImpl.java
index 73d135f..13df45b 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenterImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenterImpl.java
@@ -35,13 +35,13 @@ import org.apache.brooklyn.api.policy.PolicySpec;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.SensorEvent;
 import org.apache.brooklyn.api.sensor.SensorEventListener;
+import org.apache.brooklyn.core.effector.EffectorBody;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityPredicates;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceNotUpLogic;
 import org.apache.brooklyn.core.location.Machines;
-import org.apache.brooklyn.effector.core.EffectorBody;
 import org.apache.brooklyn.entity.group.AbstractMembershipTrackingPolicy;
 import org.apache.brooklyn.entity.group.DynamicClusterImpl;
 import org.apache.brooklyn.entity.group.DynamicGroup;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraFabric.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraFabric.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraFabric.java
index 8f993fc..5d9a9ca 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraFabric.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraFabric.java
@@ -28,7 +28,7 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.effector.core.MethodEffector;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.entity.group.DynamicFabric;
 
 import com.google.common.base.Function;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeImpl.java
index a096e33..0a7e638 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeImpl.java
@@ -36,11 +36,11 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.effector.EffectorBody;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.Machines;
 import org.apache.brooklyn.core.location.cloud.CloudLocationConfig;
-import org.apache.brooklyn.effector.core.EffectorBody;
 import org.apache.brooklyn.entity.java.JavaAppUtils;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeSshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeSshDriver.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeSshDriver.java
index 832a886..11d919e 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeSshDriver.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeSshDriver.java
@@ -31,11 +31,11 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.mgmt.TaskWrapper;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.Machines;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
index e0e91ed..bef9fa5 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
@@ -34,13 +34,13 @@ import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.policy.PolicySpec;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.config.render.RendererHints;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.entity.group.AbstractMembershipTrackingPolicy;
 import org.apache.brooklyn.entity.group.DynamicClusterImpl;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNode.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNode.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNode.java
index 0c06478..b592af8 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNode.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNode.java
@@ -28,9 +28,9 @@ import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.annotation.EffectorParam;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.config.render.RendererHints;
+import org.apache.brooklyn.core.effector.Effectors;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.core.entity.Attributes;
-import org.apache.brooklyn.effector.core.Effectors;
-import org.apache.brooklyn.effector.core.MethodEffector;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeImpl.java
index 318ac74..bed5a3d 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeImpl.java
@@ -30,10 +30,10 @@ import org.apache.brooklyn.api.location.MachineProvisioningLocation;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.SensorEvent;
 import org.apache.brooklyn.api.sensor.SensorEventListener;
+import org.apache.brooklyn.core.effector.EffectorBody;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
 import org.apache.brooklyn.core.location.cloud.CloudLocationConfig;
-import org.apache.brooklyn.effector.core.EffectorBody;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
 import org.apache.http.auth.UsernamePasswordCredentials;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
index 7a8ae35..a5a821e 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
@@ -33,13 +33,13 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.Group;
 import org.apache.brooklyn.api.location.OsDetails;
 import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.drivers.downloads.BasicDownloadRequirement;
 import org.apache.brooklyn.core.entity.drivers.downloads.DownloadProducerFromUrlAttribute;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.software.base.AbstractSoftwareProcessSshDriver;
 import org.apache.http.auth.UsernamePasswordCredentials;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBClient.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBClient.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBClient.java
index 5b8929c..4e124a7 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBClient.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBClient.java
@@ -26,7 +26,7 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.annotation.EffectorParam;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.effector.core.MethodEffector;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.entity.nosql.mongodb.sharding.MongoDBShardedDeployment;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNode.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNode.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNode.java
index e6b2258..4b43757 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNode.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNode.java
@@ -28,8 +28,8 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.annotation.EffectorParam;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.core.entity.Attributes;
-import org.apache.brooklyn.effector.core.MethodEffector;
 import org.apache.brooklyn.entity.java.UsesJava;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.sensor.core.AttributeSensorAndConfigKey;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeSshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeSshDriver.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeSshDriver.java
index 943a193..f4fda89 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeSshDriver.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/riak/RiakNodeSshDriver.java
@@ -39,9 +39,9 @@ import java.util.Map;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.api.location.OsDetails;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.java.JavaSoftwareProcessSshDriver;
 import org.apache.brooklyn.entity.software.base.lifecycle.ScriptHelper;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainer.java
----------------------------------------------------------------------
diff --git a/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainer.java b/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainer.java
index 8cad9f7..7bb7890 100644
--- a/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainer.java
+++ b/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainer.java
@@ -28,7 +28,7 @@ import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.annotation.EffectorParam;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.config.MapConfigKey;
-import org.apache.brooklyn.effector.core.MethodEffector;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.entity.java.UsesJava;
 import org.apache.brooklyn.entity.java.UsesJmx;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/osgi/src/test/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerTest.java
----------------------------------------------------------------------
diff --git a/software/osgi/src/test/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerTest.java b/software/osgi/src/test/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerTest.java
index ae525cd..624fc4e 100644
--- a/software/osgi/src/test/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerTest.java
+++ b/software/osgi/src/test/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerTest.java
@@ -26,10 +26,10 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.NoMachinesAvailableException;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.test.support.TestResourceUnavailableException;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/LoadBalancer.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/LoadBalancer.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/LoadBalancer.java
index b65e15e..e4d6262 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/LoadBalancer.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/LoadBalancer.java
@@ -27,9 +27,9 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.config.BasicConfigKey;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.effector.core.MethodEffector;
 import org.apache.brooklyn.entity.webapp.WebAppService;
 import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxController.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxController.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxController.java
index c23989e..35e28ba 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxController.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxController.java
@@ -28,7 +28,7 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.annotation.EffectorParam;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.effector.core.MethodEffector;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.entity.proxy.AbstractController;
 import org.apache.brooklyn.entity.proxy.ProxySslConfig;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/UrlMapping.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/UrlMapping.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/UrlMapping.java
index 3349edb..8ccb4a2 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/UrlMapping.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/UrlMapping.java
@@ -26,7 +26,7 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.effector.core.MethodEffector;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.entity.group.AbstractGroup;
 import org.apache.brooklyn.entity.proxy.AbstractController;
 import org.apache.brooklyn.entity.proxy.ProxySslConfig;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
index 5fe5950..10d21a1 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
@@ -29,10 +29,10 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.api.mgmt.TaskAdaptable;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.entity.group.DynamicCluster;
 import org.apache.brooklyn.entity.group.DynamicClusterImpl;
 import org.apache.brooklyn.sensor.enricher.Enrichers;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/JavaWebAppService.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/JavaWebAppService.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/JavaWebAppService.java
index 05cfdd0..650b1e9 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/JavaWebAppService.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/JavaWebAppService.java
@@ -28,7 +28,7 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.annotation.EffectorParam;
 import org.apache.brooklyn.core.config.BasicConfigKey;
-import org.apache.brooklyn.effector.core.MethodEffector;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.entity.java.UsesJava;
 import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/BrooklynDslDeferredSupplier.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/BrooklynDslDeferredSupplier.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/BrooklynDslDeferredSupplier.java
index d729206..389fe69 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/BrooklynDslDeferredSupplier.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/BrooklynDslDeferredSupplier.java
@@ -27,9 +27,9 @@ import org.apache.brooklyn.camp.spi.Assembly;
 import org.apache.brooklyn.camp.spi.AssemblyTemplate;
 import org.apache.brooklyn.camp.spi.resolve.interpret.PlanInterpretationNode;
 import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.effector.EffectorTasks;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.effector.core.EffectorTasks;
 import org.apache.brooklyn.util.core.task.DeferredSupplier;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java
index 0e9e8f51..f9fe108 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java
@@ -41,6 +41,7 @@ import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent;
 import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent.Scope;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityFunctions;
@@ -50,7 +51,6 @@ import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.mgmt.internal.EntityManagerInternal;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.core.test.entity.TestEntityImpl;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.entity.group.DynamicCluster;
 import org.apache.brooklyn.entity.software.base.SameServerEntity;
 import org.apache.brooklyn.entity.stock.BasicEntity;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/TestSensorAndEffectorInitializer.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/TestSensorAndEffectorInitializer.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/TestSensorAndEffectorInitializer.java
index f5cd9cc..85b67af 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/TestSensorAndEffectorInitializer.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/TestSensorAndEffectorInitializer.java
@@ -24,9 +24,9 @@ import org.apache.brooklyn.api.effector.Effector;
 import org.apache.brooklyn.api.entity.EntityInitializer;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.effector.EffectorBody;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.effector.core.EffectorBody;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.testng.Assert;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/VanillaBashNetcatYamlTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/VanillaBashNetcatYamlTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/VanillaBashNetcatYamlTest.java
index 3a6dcec..f3f0e50 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/VanillaBashNetcatYamlTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/VanillaBashNetcatYamlTest.java
@@ -23,11 +23,11 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityPredicates;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.collections.MutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/test/lite/CampYamlLiteTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/test/lite/CampYamlLiteTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/test/lite/CampYamlLiteTest.java
index 905c9db..cae1320 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/test/lite/CampYamlLiteTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/test/lite/CampYamlLiteTest.java
@@ -42,6 +42,8 @@ import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog;
 import org.apache.brooklyn.core.catalog.internal.CatalogDto;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.AddChildrenEffector;
+import org.apache.brooklyn.core.effector.Effectors;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
@@ -49,8 +51,6 @@ import org.apache.brooklyn.core.mgmt.osgi.OsgiStandaloneTest;
 import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.effector.core.AddChildrenEffector;
-import org.apache.brooklyn.effector.core.Effectors;
 import org.apache.brooklyn.test.support.TestResourceUnavailableException;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.ResourceUtils;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedMySqlNodeImpl.java
----------------------------------------------------------------------
diff --git a/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedMySqlNodeImpl.java b/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedMySqlNodeImpl.java
index fc0aa4c..34c8ba4 100644
--- a/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedMySqlNodeImpl.java
+++ b/usage/qa/src/main/java/org/apache/brooklyn/qa/load/SimulatedMySqlNodeImpl.java
@@ -23,7 +23,7 @@ import static java.lang.String.format;
 import java.util.concurrent.Callable;
 
 import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
 import org.apache.brooklyn.entity.database.mysql.MySqlNode;
 import org.apache.brooklyn.entity.database.mysql.MySqlNodeImpl;
 import org.apache.brooklyn.entity.database.mysql.MySqlSshDriver;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/RestMockSimpleEntity.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/RestMockSimpleEntity.java b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/RestMockSimpleEntity.java
index 740b411..e680bc1 100644
--- a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/RestMockSimpleEntity.java
+++ b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/RestMockSimpleEntity.java
@@ -27,7 +27,7 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.annotation.EffectorParam;
 import org.apache.brooklyn.core.config.BasicConfigKey;
-import org.apache.brooklyn.effector.core.MethodEffector;
+import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.entity.software.base.AbstractSoftwareProcessSshDriver;
 import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
 import org.slf4j.Logger;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/utils/test-bundles/more-entities-v1/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntity.java
----------------------------------------------------------------------
diff --git a/utils/test-bundles/more-entities-v1/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntity.java b/utils/test-bundles/more-entities-v1/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntity.java
index 81c6966..4efd1e3 100644
--- a/utils/test-bundles/more-entities-v1/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntity.java
+++ b/utils/test-bundles/more-entities-v1/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntity.java
@@ -21,7 +21,7 @@ package org.apache.brooklyn.test.osgi.entities.more;
 import org.apache.brooklyn.api.effector.Effector;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.ImplementedBy;
-import org.apache.brooklyn.effector.core.Effectors;
+import org.apache.brooklyn.core.effector.Effectors;
 
 @ImplementedBy(MoreEntityImpl.class)
 public interface MoreEntity extends Entity {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/utils/test-bundles/more-entities-v1/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntityImpl.java
----------------------------------------------------------------------
diff --git a/utils/test-bundles/more-entities-v1/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntityImpl.java b/utils/test-bundles/more-entities-v1/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntityImpl.java
index 17a8a41..c1eecd3 100644
--- a/utils/test-bundles/more-entities-v1/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntityImpl.java
+++ b/utils/test-bundles/more-entities-v1/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntityImpl.java
@@ -18,7 +18,7 @@
  */
 package org.apache.brooklyn.test.osgi.entities.more;
 
-import org.apache.brooklyn.effector.core.EffectorBody;
+import org.apache.brooklyn.core.effector.EffectorBody;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/utils/test-bundles/more-entities-v2-evil-twin/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntity.java
----------------------------------------------------------------------
diff --git a/utils/test-bundles/more-entities-v2-evil-twin/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntity.java b/utils/test-bundles/more-entities-v2-evil-twin/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntity.java
index 8a75e9a..f0ace90 100644
--- a/utils/test-bundles/more-entities-v2-evil-twin/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntity.java
+++ b/utils/test-bundles/more-entities-v2-evil-twin/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntity.java
@@ -21,7 +21,7 @@ package org.apache.brooklyn.test.osgi.entities.more;
 import org.apache.brooklyn.api.effector.Effector;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.ImplementedBy;
-import org.apache.brooklyn.effector.core.Effectors;
+import org.apache.brooklyn.core.effector.Effectors;
 
 @ImplementedBy(MoreEntityImpl.class)
 public interface MoreEntity extends Entity {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/utils/test-bundles/more-entities-v2-evil-twin/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntityImpl.java
----------------------------------------------------------------------
diff --git a/utils/test-bundles/more-entities-v2-evil-twin/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntityImpl.java b/utils/test-bundles/more-entities-v2-evil-twin/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntityImpl.java
index 497069b..d2cfa08 100644
--- a/utils/test-bundles/more-entities-v2-evil-twin/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntityImpl.java
+++ b/utils/test-bundles/more-entities-v2-evil-twin/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntityImpl.java
@@ -19,7 +19,7 @@
 package org.apache.brooklyn.test.osgi.entities.more;
 
 import org.apache.brooklyn.api.policy.PolicySpec;
-import org.apache.brooklyn.effector.core.EffectorBody;
+import org.apache.brooklyn.core.effector.EffectorBody;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/utils/test-bundles/more-entities-v2/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntity.java
----------------------------------------------------------------------
diff --git a/utils/test-bundles/more-entities-v2/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntity.java b/utils/test-bundles/more-entities-v2/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntity.java
index edd650b..2124f86 100644
--- a/utils/test-bundles/more-entities-v2/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntity.java
+++ b/utils/test-bundles/more-entities-v2/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntity.java
@@ -22,7 +22,7 @@ import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.effector.Effector;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.ImplementedBy;
-import org.apache.brooklyn.effector.core.Effectors;
+import org.apache.brooklyn.core.effector.Effectors;
 
 @Catalog(name="More Entity v2")
 @ImplementedBy(MoreEntityImpl.class)

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/utils/test-bundles/more-entities-v2/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntityImpl.java
----------------------------------------------------------------------
diff --git a/utils/test-bundles/more-entities-v2/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntityImpl.java b/utils/test-bundles/more-entities-v2/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntityImpl.java
index fa27964..0aff562 100644
--- a/utils/test-bundles/more-entities-v2/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntityImpl.java
+++ b/utils/test-bundles/more-entities-v2/src/main/java/org/apache/brooklyn/test/osgi/entities/more/MoreEntityImpl.java
@@ -19,7 +19,7 @@
 package org.apache.brooklyn.test.osgi.entities.more;
 
 import org.apache.brooklyn.api.policy.PolicySpec;
-import org.apache.brooklyn.effector.core.EffectorBody;
+import org.apache.brooklyn.core.effector.EffectorBody;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 


[13/36] incubator-brooklyn git commit: Rename o.a.b.sensor.core to o.a.b.core.sensor

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/core/Sensors.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/Sensors.java b/core/src/main/java/org/apache/brooklyn/sensor/core/Sensors.java
deleted file mode 100644
index 5e9ed81..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/core/Sensors.java
+++ /dev/null
@@ -1,164 +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.core;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.net.InetAddress;
-import java.net.URI;
-import java.net.URL;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.api.sensor.AttributeSensor.SensorPersistenceMode;
-import org.apache.brooklyn.core.config.render.RendererHints;
-import org.apache.brooklyn.util.net.UserAndHostAndPort;
-import org.apache.brooklyn.util.text.StringFunctions;
-import org.apache.brooklyn.util.time.Duration;
-import org.apache.brooklyn.util.time.Time;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Function;
-import com.google.common.net.HostAndPort;
-import com.google.common.reflect.TypeToken;
-
-public class Sensors {
-
-    @Beta
-    public static <T> Builder<T> builder(TypeToken<T> type, String name) {
-        return new Builder<T>().type(type).name(name);
-    }
-
-    @Beta
-    public static <T> Builder<T> builder(Class<T> type, String name) {
-        return new Builder<T>().type(type).name(name);
-    }
-    
-    @Beta
-    public static class Builder<T> {
-        private String name;
-        private TypeToken<T> type;
-        private String description;
-        private SensorPersistenceMode persistence;
-        
-        protected Builder() { // use builder(type, name) instead
-        }
-        public Builder<T> name(String val) {
-            this.name = checkNotNull(val, "name"); return this;
-        }
-        public Builder<T> type(Class<T> val) {
-            return type(TypeToken.of(val));
-        }
-        public Builder<T> type(TypeToken<T> val) {
-            this.type = checkNotNull(val, "type"); return this;
-        }
-        public Builder<T> description(String val) {
-            this.description = val; return this;
-        }
-        public Builder<T> persistence(SensorPersistenceMode val) {
-            this.persistence = val; return this;
-        }
-        public AttributeSensor<T> build() {
-            return new BasicAttributeSensor<T>(type, name, description, persistence);
-        }
-    }
-
-    public static <T> AttributeSensor<T> newSensor(Class<T> type, String name) {
-        return new BasicAttributeSensor<T>(type, name);
-    }
-
-    public static <T> AttributeSensor<T> newSensor(Class<T> type, String name, String description) {
-        return new BasicAttributeSensor<T>(type, name, description);
-    }
-
-    public static <T> AttributeSensor<T> newSensor(TypeToken<T> type, String name, String description) {
-        return new BasicAttributeSensor<T>(type, name, description);
-    }
-
-    public static AttributeSensor<String> newStringSensor(String name) {
-        return newSensor(String.class, name);
-    }
-
-    public static AttributeSensor<String> newStringSensor(String name, String description) {
-        return newSensor(String.class, name, description);
-    }
-
-    public static AttributeSensor<Integer> newIntegerSensor(String name) {
-        return newSensor(Integer.class, name);
-    }
-
-    public static AttributeSensor<Integer> newIntegerSensor(String name, String description) {
-        return newSensor(Integer.class, name, description);
-    }
-
-    public static AttributeSensor<Long> newLongSensor(String name) {
-        return newSensor(Long.class, name);
-    }
-
-    public static AttributeSensor<Long> newLongSensor(String name, String description) {
-        return newSensor(Long.class, name, description);
-    }
-
-    public static AttributeSensor<Double> newDoubleSensor(String name) {
-        return newSensor(Double.class, name);
-    }
-
-    public static AttributeSensor<Double> newDoubleSensor(String name, String description) {
-        return newSensor(Double.class, name, description);
-    }
-
-    public static AttributeSensor<Boolean> newBooleanSensor(String name) {
-        return newSensor(Boolean.class, name);
-    }
-
-    public static AttributeSensor<Boolean> newBooleanSensor(String name, String description) {
-        return newSensor(Boolean.class, name, description);
-    }
-
-    // Extensions to sensors
-
-    public static <T> AttributeSensor<T> newSensorRenamed(String newName, AttributeSensor<T> sensor) {
-        return new BasicAttributeSensor<T>(sensor.getTypeToken(), newName, sensor.getDescription());
-    }
-
-    public static <T> AttributeSensor<T> newSensorWithPrefix(String prefix, AttributeSensor<T> sensor) {
-        return newSensorRenamed(prefix+sensor.getName(), sensor);
-    }
-
-    // Display hints for common utility objects
-
-    static {
-        RendererHints.register(Duration.class, RendererHints.displayValue(Time.fromDurationToTimeStringRounded()));
-        RendererHints.register(HostAndPort.class, RendererHints.displayValue(StringFunctions.toStringFunction()));
-        RendererHints.register(UserAndHostAndPort.class, RendererHints.displayValue(StringFunctions.toStringFunction()));
-        RendererHints.register(InetAddress.class, RendererHints.displayValue(new Function<InetAddress,String>() {
-            @Override
-            public String apply(@Nullable InetAddress input) {
-                return input == null ? null : input.getHostAddress();
-            }
-        }));
-
-        RendererHints.register(URL.class, RendererHints.displayValue(StringFunctions.toStringFunction()));
-        RendererHints.register(URL.class, RendererHints.openWithUrl(StringFunctions.toStringFunction()));
-        RendererHints.register(URI.class, RendererHints.displayValue(StringFunctions.toStringFunction()));
-        RendererHints.register(URI.class, RendererHints.openWithUrl(StringFunctions.toStringFunction()));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/core/StaticSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/StaticSensor.java b/core/src/main/java/org/apache/brooklyn/sensor/core/StaticSensor.java
deleted file mode 100644
index 0c3a00f..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/core/StaticSensor.java
+++ /dev/null
@@ -1,72 +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.core;
-
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.mgmt.Task;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.effector.AddSensor;
-import org.apache.brooklyn.sensor.enricher.Propagator;
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.core.task.ValueResolver;
-import org.apache.brooklyn.util.guava.Maybe;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Supplier;
-
-/** 
- * Provides an initializer/feed which simply sets a given value.
- * <p>
- * {@link Task}/{@link Supplier} values are resolved when written,
- * unlike config values which are resolved on each read.
- * <p>
- * This supports a {@link StaticSensor#SENSOR_PERIOD} 
- * which can be useful if the supplied value is such a function.
- * However when the source is another sensor,
- * consider using {@link Propagator} which listens for changes instead. */
-public class StaticSensor<T> extends AddSensor<T> {
-
-    private static final Logger log = LoggerFactory.getLogger(StaticSensor.class);
-    
-    public static final ConfigKey<Object> STATIC_VALUE = ConfigKeys.newConfigKey(Object.class, "static.value");
-
-    private final Object value;
-
-    public StaticSensor(ConfigBag params) {
-        super(params);
-        value = params.get(STATIC_VALUE);
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public void apply(EntityLocal entity) {
-        super.apply(entity);
-        
-        Maybe<T> v = Tasks.resolving(value).as((Class<T>)sensor.getType()).timeout(ValueResolver.PRETTY_QUICK_WAIT).getMaybe();
-        if (v.isPresent()) {
-            log.debug(this+" setting sensor "+sensor+" to "+v.get());
-            entity.setAttribute(sensor, v.get());
-        } else {
-            log.debug(this+" not setting sensor "+sensor+"; cannot resolve "+value);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/core/TemplatedStringAttributeSensorAndConfigKey.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/TemplatedStringAttributeSensorAndConfigKey.java b/core/src/main/java/org/apache/brooklyn/sensor/core/TemplatedStringAttributeSensorAndConfigKey.java
deleted file mode 100644
index 27367c3..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/core/TemplatedStringAttributeSensorAndConfigKey.java
+++ /dev/null
@@ -1,66 +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.core;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.mgmt.ManagementContext;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
-import org.apache.brooklyn.util.core.text.TemplateProcessor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.ImmutableMap;
-
-/**
- * A {@link ConfigKey} which takes a freemarker-templated string,
- * and whose value is converted to a sensor by processing the template 
- * with access to config and methods on the entity where it is set.
- */
-public class TemplatedStringAttributeSensorAndConfigKey extends BasicAttributeSensorAndConfigKey<String> {
-    private static final long serialVersionUID = 4680651022807491321L;
-    
-    public static final Logger LOG = LoggerFactory.getLogger(TemplatedStringAttributeSensorAndConfigKey.class);
-
-    public TemplatedStringAttributeSensorAndConfigKey(String name) {
-        this(name, name, null);
-    }
-    public TemplatedStringAttributeSensorAndConfigKey(String name, String description) {
-        this(name, description, null);
-    }
-    public TemplatedStringAttributeSensorAndConfigKey(String name, String description, String defaultValue) {
-        super(String.class, name, description, defaultValue);
-    }
-    public TemplatedStringAttributeSensorAndConfigKey(TemplatedStringAttributeSensorAndConfigKey orig, String defaultValue) {
-        super(orig, defaultValue);
-    }
-    
-    @Override
-    protected String convertConfigToSensor(String value, Entity entity) {
-        if (value == null) return null;
-        return TemplateProcessor.processTemplateContents(value, (EntityInternal)entity, ImmutableMap.<String,Object>of());
-    }
-    
-    @Override
-    protected String convertConfigToSensor(String value, ManagementContext managementContext) {
-        if (value == null) return null;
-        return TemplateProcessor.processTemplateContents(value, (ManagementContextInternal)managementContext, ImmutableMap.<String,Object>of());
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractTransformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractTransformer.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractTransformer.java
index 09cf404..1ff7938 100644
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractTransformer.java
+++ b/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractTransformer.java
@@ -26,7 +26,7 @@ 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.sensor.core.BasicSensorEvent;
+import org.apache.brooklyn.core.sensor.BasicSensorEvent;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractTypeTransformingEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractTypeTransformingEnricher.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractTypeTransformingEnricher.java
index c022da7..f66004c 100644
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractTypeTransformingEnricher.java
+++ b/core/src/main/java/org/apache/brooklyn/sensor/enricher/AbstractTypeTransformingEnricher.java
@@ -23,7 +23,7 @@ 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.SensorEventListener;
-import org.apache.brooklyn.sensor.core.BasicSensorEvent;
+import org.apache.brooklyn.core.sensor.BasicSensorEvent;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/enricher/AddingEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/AddingEnricher.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/AddingEnricher.java
index 067c568..997f974 100644
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/AddingEnricher.java
+++ b/core/src/main/java/org/apache/brooklyn/sensor/enricher/AddingEnricher.java
@@ -23,7 +23,7 @@ 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.sensor.core.BasicSensorEvent;
+import org.apache.brooklyn.core.sensor.BasicSensorEvent;
 
 /** 
  * enricher which adds multiple sensors on an entity to produce a new sensor

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/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
index 583ee7d..823b8b7 100644
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Combiner.java
+++ b/core/src/main/java/org/apache/brooklyn/sensor/enricher/Combiner.java
@@ -35,7 +35,7 @@ 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.sensor.core.BasicSensorEvent;
+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;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/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
index 4ab4fe9..c6d9329 100644
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Joiner.java
+++ b/core/src/main/java/org/apache/brooklyn/sensor/enricher/Joiner.java
@@ -28,7 +28,7 @@ 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.sensor.core.BasicSensorEvent;
+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;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/feed/ConfigToAttributes.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/ConfigToAttributes.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/ConfigToAttributes.java
index b3c156a..7938cc4 100644
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/ConfigToAttributes.java
+++ b/core/src/main/java/org/apache/brooklyn/sensor/feed/ConfigToAttributes.java
@@ -21,8 +21,8 @@ package org.apache.brooklyn.sensor.feed;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.sensor.Sensor;
-import org.apache.brooklyn.sensor.core.AttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.TemplatedStringAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.TemplatedStringAttributeSensorAndConfigKey;
 
 
 /** Simple config adapter for setting {@link AttributeSensorAndConfigKey} sensor values from the config value or config default */ 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/feed/FeedConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/FeedConfig.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/FeedConfig.java
index d3f7597..32ea2ab 100644
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/FeedConfig.java
+++ b/core/src/main/java/org/apache/brooklyn/sensor/feed/FeedConfig.java
@@ -22,7 +22,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
 
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.guava.Functionals;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeed.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeed.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeed.java
index 95aba9f..e9767d9 100644
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeed.java
+++ b/core/src/main/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeed.java
@@ -42,10 +42,10 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.effector.EffectorTasks;
 import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.feed.AbstractFeed;
 import org.apache.brooklyn.sensor.feed.PollHandler;
 import org.apache.brooklyn.sensor.feed.Poller;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/util/core/flags/TypeCoercions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/flags/TypeCoercions.java b/core/src/main/java/org/apache/brooklyn/util/core/flags/TypeCoercions.java
index 51b0456..ec49de7 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/flags/TypeCoercions.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/flags/TypeCoercions.java
@@ -50,7 +50,7 @@ import org.apache.brooklyn.core.entity.factory.ConfigurableEntityFactory;
 import org.apache.brooklyn.core.entity.factory.ConfigurableEntityFactoryFromEntityFactory;
 import org.apache.brooklyn.core.internal.BrooklynInitialization;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.util.JavaGroovyEquivalents;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.collections.QuorumCheck;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/util/core/text/TemplateProcessor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/text/TemplateProcessor.java b/core/src/main/java/org/apache/brooklyn/util/core/text/TemplateProcessor.java
index afa2f71..58efcd4 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/text/TemplateProcessor.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/text/TemplateProcessor.java
@@ -34,8 +34,8 @@ import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.text.Strings;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/config/MapListAndOtherStructuredConfigKeyTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/config/MapListAndOtherStructuredConfigKeyTest.groovy b/core/src/test/java/org/apache/brooklyn/core/config/MapListAndOtherStructuredConfigKeyTest.groovy
index e57c8cb..8516df5 100644
--- a/core/src/test/java/org/apache/brooklyn/core/config/MapListAndOtherStructuredConfigKeyTest.groovy
+++ b/core/src/test/java/org/apache/brooklyn/core/config/MapListAndOtherStructuredConfigKeyTest.groovy
@@ -33,7 +33,7 @@ import org.apache.brooklyn.core.test.entity.TestApplication
 import org.apache.brooklyn.core.test.entity.TestEntity
 import org.apache.brooklyn.core.entity.Entities
 import org.apache.brooklyn.core.location.SimulatedLocation
-import org.apache.brooklyn.sensor.core.DependentConfiguration
+import org.apache.brooklyn.core.sensor.DependentConfiguration
 import org.apache.brooklyn.util.collections.MutableMap
 import org.apache.brooklyn.util.core.task.DeferredSupplier
 import org.apache.brooklyn.util.exceptions.Exceptions

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/entity/AttributeMapTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/AttributeMapTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/AttributeMapTest.java
index 565b34b..21529c8 100644
--- a/core/src/test/java/org/apache/brooklyn/core/entity/AttributeMapTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/AttributeMapTest.java
@@ -32,10 +32,10 @@ import java.util.concurrent.Future;
 import org.apache.brooklyn.api.entity.Application;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.AttributeMap;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntityImpl;
-import org.apache.brooklyn.sensor.core.AttributeMap;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.guava.Maybe;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/entity/AttributeTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/AttributeTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/AttributeTest.java
index 614a275..68fe527 100644
--- a/core/src/test/java/org/apache/brooklyn/core/entity/AttributeTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/AttributeTest.java
@@ -22,8 +22,8 @@ import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNull;
 
 import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
 import org.apache.brooklyn.core.test.entity.TestEntityImpl;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/entity/ConfigEntityInheritanceTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/ConfigEntityInheritanceTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/ConfigEntityInheritanceTest.java
index 2a8ae20..afcd340 100644
--- a/core/src/test/java/org/apache/brooklyn/core/entity/ConfigEntityInheritanceTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/ConfigEntityInheritanceTest.java
@@ -26,9 +26,9 @@ import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.internal.ConfigMapTest.MyOtherEntity;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey.IntegerAttributeSensorAndConfigKey;
 import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.apache.brooklyn.sensor.core.AttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey.IntegerAttributeSensorAndConfigKey;
 import org.testng.Assert;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/entity/DependentConfigurationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/DependentConfigurationTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/DependentConfigurationTest.java
index 2c681f3..45fac8f 100644
--- a/core/src/test/java/org/apache/brooklyn/core/entity/DependentConfigurationTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/DependentConfigurationTest.java
@@ -35,9 +35,9 @@ import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.collections.MutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/entity/EntitySubscriptionTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/EntitySubscriptionTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/EntitySubscriptionTest.java
index 6e2bd89..599d28c 100644
--- a/core/src/test/java/org/apache/brooklyn/core/entity/EntitySubscriptionTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/EntitySubscriptionTest.java
@@ -25,10 +25,10 @@ import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.mgmt.SubscriptionHandle;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.SimulatedLocation;
+import org.apache.brooklyn.core.sensor.BasicSensorEvent;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.entity.group.BasicGroup;
-import org.apache.brooklyn.sensor.core.BasicSensorEvent;
 import org.apache.brooklyn.test.Asserts;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/entity/EntityTypeTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/EntityTypeTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/EntityTypeTest.java
index cead05a..5851c35 100644
--- a/core/src/test/java/org/apache/brooklyn/core/entity/EntityTypeTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/EntityTypeTest.java
@@ -51,11 +51,11 @@ import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.sensor.BasicSensorEvent;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.core.test.entity.TestEntityImpl;
-import org.apache.brooklyn.sensor.core.BasicSensorEvent;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.testng.annotations.BeforeMethod;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/entity/hello/HelloEntity.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/hello/HelloEntity.java b/core/src/test/java/org/apache/brooklyn/core/entity/hello/HelloEntity.java
index a217514..5490868 100644
--- a/core/src/test/java/org/apache/brooklyn/core/entity/hello/HelloEntity.java
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/hello/HelloEntity.java
@@ -26,9 +26,9 @@ import org.apache.brooklyn.core.annotation.Effector;
 import org.apache.brooklyn.core.annotation.EffectorParam;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.effector.MethodEffector;
+import org.apache.brooklyn.core.sensor.BasicSensor;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.group.AbstractGroup;
-import org.apache.brooklyn.sensor.core.BasicSensor;
-import org.apache.brooklyn.sensor.core.Sensors;
 
 @ImplementedBy(HelloEntityImpl.class)
 public interface HelloEntity extends AbstractGroup {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/entity/hello/LocalEntitiesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/hello/LocalEntitiesTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/hello/LocalEntitiesTest.java
index 9fef5ba..28ee8c1 100644
--- a/core/src/test/java/org/apache/brooklyn/core/entity/hello/LocalEntitiesTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/hello/LocalEntitiesTest.java
@@ -18,8 +18,8 @@
  */
 package org.apache.brooklyn.core.entity.hello;
 
-import static org.apache.brooklyn.sensor.core.DependentConfiguration.attributeWhenReady;
-import static org.apache.brooklyn.sensor.core.DependentConfiguration.transform;
+import static org.apache.brooklyn.core.sensor.DependentConfiguration.attributeWhenReady;
+import static org.apache.brooklyn.core.sensor.DependentConfiguration.transform;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertNull;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/entity/internal/ConfigMapTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/internal/ConfigMapTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/internal/ConfigMapTest.java
index 448ca07..0a0b3a2 100644
--- a/core/src/test/java/org/apache/brooklyn/core/entity/internal/ConfigMapTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/internal/ConfigMapTest.java
@@ -41,8 +41,8 @@ import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.config.ConfigPredicates;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey.IntegerAttributeSensorAndConfigKey;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey.IntegerAttributeSensorAndConfigKey;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.task.BasicTask;
 import org.apache.brooklyn.util.core.task.DeferredSupplier;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/entity/internal/EntityConfigMapUsageLegacyTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/internal/EntityConfigMapUsageLegacyTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/internal/EntityConfigMapUsageLegacyTest.java
index dcd40ee..11e3ca6 100644
--- a/core/src/test/java/org/apache/brooklyn/core/entity/internal/EntityConfigMapUsageLegacyTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/internal/EntityConfigMapUsageLegacyTest.java
@@ -25,7 +25,6 @@ import static org.testng.Assert.fail;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
 
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.time.Time;
 import org.testng.annotations.Test;
@@ -33,6 +32,7 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.SimulatedLocation;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.core.test.entity.TestEntityImpl;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/entity/internal/EntityConfigMapUsageTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/internal/EntityConfigMapUsageTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/internal/EntityConfigMapUsageTest.java
index e5b6299..9af2919 100644
--- a/core/src/test/java/org/apache/brooklyn/core/entity/internal/EntityConfigMapUsageTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/internal/EntityConfigMapUsageTest.java
@@ -32,9 +32,9 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.BasicConfigKey;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.SimulatedLocation;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/entity/lifecycle/ServiceStateLogicTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/lifecycle/ServiceStateLogicTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/lifecycle/ServiceStateLogicTest.java
index f461e4b..33d5e1c 100644
--- a/core/src/test/java/org/apache/brooklyn/core/entity/lifecycle/ServiceStateLogicTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/lifecycle/ServiceStateLogicTest.java
@@ -32,11 +32,11 @@ import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ComputeServiceIndicatorsFromChildrenAndMembers;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceNotUpLogic;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceProblemsLogic;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.core.test.entity.TestEntityImpl.TestEntityWithoutEnrichers;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.collections.QuorumCheck.QuorumChecks;
 import org.apache.brooklyn.util.exceptions.Exceptions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/location/TestPortSupplierLocation.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/location/TestPortSupplierLocation.java b/core/src/test/java/org/apache/brooklyn/core/location/TestPortSupplierLocation.java
index 6b64cc1..a5b4294 100644
--- a/core/src/test/java/org/apache/brooklyn/core/location/TestPortSupplierLocation.java
+++ b/core/src/test/java/org/apache/brooklyn/core/location/TestPortSupplierLocation.java
@@ -22,9 +22,9 @@ import static org.testng.Assert.assertEquals;
 
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.core.PortAttributeSensorAndConfigKey;
 import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/location/access/PortForwardManagerRebindTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/location/access/PortForwardManagerRebindTest.java b/core/src/test/java/org/apache/brooklyn/core/location/access/PortForwardManagerRebindTest.java
index f123342..f14c4a3 100644
--- a/core/src/test/java/org/apache/brooklyn/core/location/access/PortForwardManagerRebindTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/location/access/PortForwardManagerRebindTest.java
@@ -37,9 +37,9 @@ import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore;
 import org.apache.brooklyn.core.mgmt.rebind.RebindOptions;
 import org.apache.brooklyn.core.mgmt.rebind.RebindTestFixtureWithApp;
 import org.apache.brooklyn.core.mgmt.rebind.RebindTestUtils;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.core.test.entity.TestEntityImpl;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.util.net.Networking;
 import org.apache.brooklyn.util.os.Os;
 import org.apache.brooklyn.util.text.Identifiers;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/mgmt/internal/EntityExecutionManagerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/internal/EntityExecutionManagerTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/internal/EntityExecutionManagerTest.java
index d69294b..2bc73cb 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/internal/EntityExecutionManagerTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/internal/EntityExecutionManagerTest.java
@@ -43,10 +43,10 @@ import org.apache.brooklyn.core.mgmt.BrooklynTaskTags.WrappedEntity;
 import org.apache.brooklyn.core.mgmt.internal.BrooklynGarbageCollector;
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
 import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.task.BasicExecutionManager;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindCatalogEntityTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindCatalogEntityTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindCatalogEntityTest.java
index d437e92..4d03e05 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindCatalogEntityTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindCatalogEntityTest.java
@@ -42,7 +42,7 @@ import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.StartableApplication;
 import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.test.support.TestResourceUnavailableException;
 import org.apache.brooklyn.util.core.javalang.UrlClassLoader;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEnricherTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEnricherTest.java
index 4afb361..c4d295a 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEnricherTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEnricherTest.java
@@ -38,11 +38,11 @@ import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.EntityPredicates;
 import org.apache.brooklyn.core.location.SimulatedLocation;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.core.test.entity.TestEntityImpl;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.enricher.AbstractEnricher;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.test.Asserts;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEntityTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEntityTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEntityTest.java
index a427995..f912e55 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEntityTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEntityTest.java
@@ -62,15 +62,15 @@ import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.location.LocationConfigTest.MyLocation;
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
 import org.apache.brooklyn.core.mgmt.rebind.BasicEntityRebindSupport;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicSensorEvent;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.core.test.entity.TestEntityImpl;
 import org.apache.brooklyn.entity.group.AbstractGroupImpl;
 import org.apache.brooklyn.entity.group.BasicGroup;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
-import org.apache.brooklyn.sensor.core.BasicSensorEvent;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFeedTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFeedTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFeedTest.java
index cdfd87d..f0c6551 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFeedTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFeedTest.java
@@ -32,9 +32,9 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.mgmt.internal.BrooklynGarbageCollector;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.core.test.entity.TestEntityImpl.TestEntityWithoutEnrichers;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.feed.function.FunctionFeed;
 import org.apache.brooklyn.sensor.feed.function.FunctionPollConfig;
 import org.apache.brooklyn.sensor.feed.http.HttpFeed;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/policy/basic/PolicyConfigTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/policy/basic/PolicyConfigTest.java b/core/src/test/java/org/apache/brooklyn/core/policy/basic/PolicyConfigTest.java
index cd07bc5..0b5c877 100644
--- a/core/src/test/java/org/apache/brooklyn/core/policy/basic/PolicyConfigTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/policy/basic/PolicyConfigTest.java
@@ -27,9 +27,9 @@ import java.util.concurrent.CountDownLatch;
 
 import org.apache.brooklyn.core.config.BasicConfigKey;
 import org.apache.brooklyn.core.policy.basic.BasicPolicyTest.MyPolicy;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.core.DependentConfiguration;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.testng.annotations.Test;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/policy/basic/PolicySubscriptionTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/policy/basic/PolicySubscriptionTest.java b/core/src/test/java/org/apache/brooklyn/core/policy/basic/PolicySubscriptionTest.java
index 6ed6918..ed4a9c0 100644
--- a/core/src/test/java/org/apache/brooklyn/core/policy/basic/PolicySubscriptionTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/policy/basic/PolicySubscriptionTest.java
@@ -25,9 +25,9 @@ import org.apache.brooklyn.api.mgmt.SubscriptionHandle;
 import org.apache.brooklyn.core.entity.RecordingSensorEventListener;
 import org.apache.brooklyn.core.location.SimulatedLocation;
 import org.apache.brooklyn.core.policy.AbstractPolicy;
+import org.apache.brooklyn.core.sensor.BasicSensorEvent;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.core.BasicSensorEvent;
 import org.apache.brooklyn.test.Asserts;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/sensor/HttpRequestSensorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/sensor/HttpRequestSensorTest.java b/core/src/test/java/org/apache/brooklyn/core/sensor/HttpRequestSensorTest.java
new file mode 100644
index 0000000..4715594
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/sensor/HttpRequestSensorTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.core.sensor;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.HttpRequestSensor;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.test.TestHttpRequestHandler;
+import org.apache.brooklyn.core.test.TestHttpServer;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.time.Duration;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+
+public class HttpRequestSensorTest {
+    final static AttributeSensor<String> SENSOR_STRING = Sensors.newStringSensor("aString");
+    final static String TARGET_TYPE = "java.lang.String";
+
+    private TestApplication app;
+    private EntityLocal entity;
+
+    private TestHttpServer server;
+    private String serverUrl;
+
+    @BeforeClass(alwaysRun=true)
+    public void setUp() throws Exception {
+        server = new TestHttpServer()
+            .handler("/myKey/myValue", new TestHttpRequestHandler().header("Content-Type", "application/json").response("{\"myKey\":\"myValue\"}"))
+            .start();
+        serverUrl = server.getUrl();
+
+        app = TestApplication.Factory.newManagedInstanceForTests();
+        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class)
+                .location(app.newLocalhostProvisioningLocation().obtain()));
+        app.start(ImmutableList.<Location>of());
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+        server.stop();
+    }
+
+    @Test
+    public void testHttpSensor() throws Exception {
+        HttpRequestSensor<Integer> sensor = new HttpRequestSensor<Integer>(ConfigBag.newInstance()
+                .configure(HttpRequestSensor.SENSOR_PERIOD, Duration.millis(100))
+                .configure(HttpRequestSensor.SENSOR_NAME, SENSOR_STRING.getName())
+                .configure(HttpRequestSensor.SENSOR_TYPE, TARGET_TYPE)
+                .configure(HttpRequestSensor.JSON_PATH, "$.myKey")
+                .configure(HttpRequestSensor.SENSOR_URI, serverUrl + "/myKey/myValue"));
+        sensor.apply(entity);
+        entity.setAttribute(Attributes.SERVICE_UP, true);
+
+        EntityTestUtils.assertAttributeEqualsEventually(entity, SENSOR_STRING, "myValue");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/sensor/StaticSensorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/sensor/StaticSensorTest.java b/core/src/test/java/org/apache/brooklyn/core/sensor/StaticSensorTest.java
new file mode 100644
index 0000000..1e6efb1
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/sensor/StaticSensorTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.core.sensor;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.sensor.StaticSensor;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.entity.stock.BasicEntity;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+public class StaticSensorTest extends BrooklynAppUnitTestSupport {
+
+    @Test
+    public void testAddsStaticSensorOfTypeString() {
+        BasicEntity entity = app.createAndManageChild(EntitySpec.create(BasicEntity.class)
+                .addInitializer(new StaticSensor<String>(ConfigBag.newInstance(ImmutableMap.of(
+                        StaticSensor.SENSOR_NAME, "myname",
+                        StaticSensor.SENSOR_TYPE, String.class.getName(),
+                        StaticSensor.STATIC_VALUE, "myval")))));
+        
+        EntityTestUtils.assertAttributeEquals(entity, Sensors.newSensor(String.class, "myname"), "myval");
+    }
+    
+    @Test
+    public void testAddsStaticSensorOfTypeInteger() {
+        BasicEntity entity = app.createAndManageChild(EntitySpec.create(BasicEntity.class)
+                .addInitializer(new StaticSensor<Integer>(ConfigBag.newInstance(ImmutableMap.of(
+                        StaticSensor.SENSOR_NAME, "myname",
+                        StaticSensor.SENSOR_TYPE, Integer.class.getName(),
+                        StaticSensor.STATIC_VALUE, "1")))));
+        
+        EntityTestUtils.assertAttributeEquals(entity, Sensors.newSensor(Integer.class, "myname"), 1);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/test/entity/TestApplication.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/test/entity/TestApplication.java b/core/src/test/java/org/apache/brooklyn/core/test/entity/TestApplication.java
index 2521b1f..974d4e6 100644
--- a/core/src/test/java/org/apache/brooklyn/core/test/entity/TestApplication.java
+++ b/core/src/test/java/org/apache/brooklyn/core/test/entity/TestApplication.java
@@ -29,8 +29,8 @@ import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.StartableApplication;
 import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
 import org.apache.brooklyn.core.location.SimulatedLocation;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
-import org.apache.brooklyn.sensor.core.Sensors;
 
 /**
  * Mock application for testing.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/core/test/entity/TestEntity.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/test/entity/TestEntity.java b/core/src/test/java/org/apache/brooklyn/core/test/entity/TestEntity.java
index 8c185a0..be8ad3d 100644
--- a/core/src/test/java/org/apache/brooklyn/core/test/entity/TestEntity.java
+++ b/core/src/test/java/org/apache/brooklyn/core/test/entity/TestEntity.java
@@ -41,8 +41,8 @@ import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.sensor.core.BasicNotificationSensor;
-import org.apache.brooklyn.sensor.core.Sensors;
+import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.testng.collections.Lists;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/entity/group/DynamicGroupTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/entity/group/DynamicGroupTest.java b/core/src/test/java/org/apache/brooklyn/entity/group/DynamicGroupTest.java
index 7c43835..1b7ec97 100644
--- a/core/src/test/java/org/apache/brooklyn/entity/group/DynamicGroupTest.java
+++ b/core/src/test/java/org/apache/brooklyn/entity/group/DynamicGroupTest.java
@@ -42,12 +42,12 @@ import org.apache.brooklyn.api.sensor.SensorEventListener;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityPredicates;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.entity.group.AbstractGroup;
 import org.apache.brooklyn.entity.group.DynamicGroup;
 import org.apache.brooklyn.entity.group.DynamicGroupImpl;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.exceptions.Exceptions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/entity/group/DynamicMultiGroupTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/entity/group/DynamicMultiGroupTest.java b/core/src/test/java/org/apache/brooklyn/entity/group/DynamicMultiGroupTest.java
index f783b49..d0d1235 100644
--- a/core/src/test/java/org/apache/brooklyn/entity/group/DynamicMultiGroupTest.java
+++ b/core/src/test/java/org/apache/brooklyn/entity/group/DynamicMultiGroupTest.java
@@ -37,12 +37,12 @@ import org.apache.brooklyn.api.sensor.SensorEventListener;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
 import org.apache.brooklyn.core.location.SimulatedLocation;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.entity.group.BasicGroup;
 import org.apache.brooklyn.entity.group.DynamicMultiGroup;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.test.Asserts;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/entity/stock/DataEntityTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/entity/stock/DataEntityTest.java b/core/src/test/java/org/apache/brooklyn/entity/stock/DataEntityTest.java
index f2c4a23..5d19d43 100644
--- a/core/src/test/java/org/apache/brooklyn/entity/stock/DataEntityTest.java
+++ b/core/src/test/java/org/apache/brooklyn/entity/stock/DataEntityTest.java
@@ -30,10 +30,10 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
 import org.apache.brooklyn.core.location.SimulatedLocation;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.entity.stock.DataEntity;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.collections.MutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/sensor/core/HttpRequestSensorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/core/HttpRequestSensorTest.java b/core/src/test/java/org/apache/brooklyn/sensor/core/HttpRequestSensorTest.java
deleted file mode 100644
index 1ac4432..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/core/HttpRequestSensorTest.java
+++ /dev/null
@@ -1,85 +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.core;
-
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.core.entity.Attributes;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.test.TestHttpRequestHandler;
-import org.apache.brooklyn.core.test.TestHttpServer;
-import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.core.HttpRequestSensor;
-import org.apache.brooklyn.sensor.core.Sensors;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.time.Duration;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.ImmutableList;
-
-public class HttpRequestSensorTest {
-    final static AttributeSensor<String> SENSOR_STRING = Sensors.newStringSensor("aString");
-    final static String TARGET_TYPE = "java.lang.String";
-
-    private TestApplication app;
-    private EntityLocal entity;
-
-    private TestHttpServer server;
-    private String serverUrl;
-
-    @BeforeClass(alwaysRun=true)
-    public void setUp() throws Exception {
-        server = new TestHttpServer()
-            .handler("/myKey/myValue", new TestHttpRequestHandler().header("Content-Type", "application/json").response("{\"myKey\":\"myValue\"}"))
-            .start();
-        serverUrl = server.getUrl();
-
-        app = TestApplication.Factory.newManagedInstanceForTests();
-        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class)
-                .location(app.newLocalhostProvisioningLocation().obtain()));
-        app.start(ImmutableList.<Location>of());
-    }
-
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        if (app != null) Entities.destroyAll(app.getManagementContext());
-        server.stop();
-    }
-
-    @Test
-    public void testHttpSensor() throws Exception {
-        HttpRequestSensor<Integer> sensor = new HttpRequestSensor<Integer>(ConfigBag.newInstance()
-                .configure(HttpRequestSensor.SENSOR_PERIOD, Duration.millis(100))
-                .configure(HttpRequestSensor.SENSOR_NAME, SENSOR_STRING.getName())
-                .configure(HttpRequestSensor.SENSOR_TYPE, TARGET_TYPE)
-                .configure(HttpRequestSensor.JSON_PATH, "$.myKey")
-                .configure(HttpRequestSensor.SENSOR_URI, serverUrl + "/myKey/myValue"));
-        sensor.apply(entity);
-        entity.setAttribute(Attributes.SERVICE_UP, true);
-
-        EntityTestUtils.assertAttributeEqualsEventually(entity, SENSOR_STRING, "myValue");
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/sensor/core/StaticSensorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/core/StaticSensorTest.java b/core/src/test/java/org/apache/brooklyn/sensor/core/StaticSensorTest.java
deleted file mode 100644
index a62d985..0000000
--- a/core/src/test/java/org/apache/brooklyn/sensor/core/StaticSensorTest.java
+++ /dev/null
@@ -1,55 +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.core;
-
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.entity.stock.BasicEntity;
-import org.apache.brooklyn.sensor.core.Sensors;
-import org.apache.brooklyn.sensor.core.StaticSensor;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.ImmutableMap;
-
-public class StaticSensorTest extends BrooklynAppUnitTestSupport {
-
-    @Test
-    public void testAddsStaticSensorOfTypeString() {
-        BasicEntity entity = app.createAndManageChild(EntitySpec.create(BasicEntity.class)
-                .addInitializer(new StaticSensor<String>(ConfigBag.newInstance(ImmutableMap.of(
-                        StaticSensor.SENSOR_NAME, "myname",
-                        StaticSensor.SENSOR_TYPE, String.class.getName(),
-                        StaticSensor.STATIC_VALUE, "myval")))));
-        
-        EntityTestUtils.assertAttributeEquals(entity, Sensors.newSensor(String.class, "myname"), "myval");
-    }
-    
-    @Test
-    public void testAddsStaticSensorOfTypeInteger() {
-        BasicEntity entity = app.createAndManageChild(EntitySpec.create(BasicEntity.class)
-                .addInitializer(new StaticSensor<Integer>(ConfigBag.newInstance(ImmutableMap.of(
-                        StaticSensor.SENSOR_NAME, "myname",
-                        StaticSensor.SENSOR_TYPE, Integer.class.getName(),
-                        StaticSensor.STATIC_VALUE, "1")))));
-        
-        EntityTestUtils.assertAttributeEquals(entity, Sensors.newSensor(Integer.class, "myname"), 1);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricherDeprecatedTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricherDeprecatedTest.groovy b/core/src/test/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricherDeprecatedTest.groovy
index 0700c91..b35c329 100644
--- a/core/src/test/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricherDeprecatedTest.groovy
+++ b/core/src/test/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricherDeprecatedTest.groovy
@@ -27,7 +27,7 @@ import org.apache.brooklyn.core.test.entity.TestEntity
 import org.apache.brooklyn.core.entity.Entities
 import org.apache.brooklyn.entity.group.BasicGroup
 import org.apache.brooklyn.core.location.SimulatedLocation
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor
 import org.apache.brooklyn.test.TestUtils
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricherTest.java b/core/src/test/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricherTest.java
index 05e0fe3..30737b7 100644
--- a/core/src/test/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricherTest.java
+++ b/core/src/test/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricherTest.java
@@ -26,10 +26,10 @@ import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.SimulatedLocation;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.entity.group.BasicGroup;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.collections.MutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/sensor/enricher/EnrichersTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/enricher/EnrichersTest.java b/core/src/test/java/org/apache/brooklyn/sensor/enricher/EnrichersTest.java
index 1307bb5..ff76342 100644
--- a/core/src/test/java/org/apache/brooklyn/sensor/enricher/EnrichersTest.java
+++ b/core/src/test/java/org/apache/brooklyn/sensor/enricher/EnrichersTest.java
@@ -29,10 +29,10 @@ import org.apache.brooklyn.api.sensor.SensorEvent;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityAdjuncts;
 import org.apache.brooklyn.core.entity.RecordingSensorEventListener;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.entity.group.BasicGroup;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.test.EntityTestUtils;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricherDeprecatedTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricherDeprecatedTest.java b/core/src/test/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricherDeprecatedTest.java
index 589c0fb..9b55006 100644
--- a/core/src/test/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricherDeprecatedTest.java
+++ b/core/src/test/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricherDeprecatedTest.java
@@ -24,9 +24,9 @@ import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.SensorEvent;
 import org.apache.brooklyn.api.sensor.SensorEventListener;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.enricher.SensorPropagatingEnricher;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.test.EntityTestUtils;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricherTest.java b/core/src/test/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricherTest.java
index 241e581..82067c4 100644
--- a/core/src/test/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricherTest.java
+++ b/core/src/test/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricherTest.java
@@ -25,10 +25,10 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.EnricherSpec;
 import org.apache.brooklyn.api.sensor.SensorEvent;
 import org.apache.brooklyn.api.sensor.SensorEventListener;
+import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.core.BasicNotificationSensor;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.sensor.enricher.Propagator;
 import org.apache.brooklyn.test.Asserts;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/sensor/enricher/TransformingEnricherDeprecatedTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/enricher/TransformingEnricherDeprecatedTest.groovy b/core/src/test/java/org/apache/brooklyn/sensor/enricher/TransformingEnricherDeprecatedTest.groovy
index 2883a05..9db0d37 100644
--- a/core/src/test/java/org/apache/brooklyn/sensor/enricher/TransformingEnricherDeprecatedTest.groovy
+++ b/core/src/test/java/org/apache/brooklyn/sensor/enricher/TransformingEnricherDeprecatedTest.groovy
@@ -26,7 +26,7 @@ import org.apache.brooklyn.core.test.entity.TestApplication
 import org.apache.brooklyn.core.test.entity.TestEntity
 import org.apache.brooklyn.core.entity.Entities
 import org.apache.brooklyn.core.location.SimulatedLocation
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor
 import org.apache.brooklyn.test.TestUtils
 import org.apache.brooklyn.util.collections.MutableMap
 import org.slf4j.Logger

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/sensor/enricher/TransformingEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/enricher/TransformingEnricherTest.java b/core/src/test/java/org/apache/brooklyn/sensor/enricher/TransformingEnricherTest.java
index 70d5af5..d020a25 100644
--- a/core/src/test/java/org/apache/brooklyn/sensor/enricher/TransformingEnricherTest.java
+++ b/core/src/test/java/org/apache/brooklyn/sensor/enricher/TransformingEnricherTest.java
@@ -21,9 +21,9 @@ package org.apache.brooklyn.sensor.enricher;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.location.SimulatedLocation;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
 import org.apache.brooklyn.sensor.enricher.Enrichers;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.util.math.MathFunctions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/sensor/enricher/YamlRollingTimeWindowMeanEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/enricher/YamlRollingTimeWindowMeanEnricherTest.java b/core/src/test/java/org/apache/brooklyn/sensor/enricher/YamlRollingTimeWindowMeanEnricherTest.java
index 96644a6..e7fbcd6 100644
--- a/core/src/test/java/org/apache/brooklyn/sensor/enricher/YamlRollingTimeWindowMeanEnricherTest.java
+++ b/core/src/test/java/org/apache/brooklyn/sensor/enricher/YamlRollingTimeWindowMeanEnricherTest.java
@@ -26,9 +26,9 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.EnricherSpec;
 import org.apache.brooklyn.core.entity.AbstractApplication;
 import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicSensorEvent;
 import org.apache.brooklyn.entity.stock.BasicEntity;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
-import org.apache.brooklyn.sensor.core.BasicSensorEvent;
 import org.apache.brooklyn.sensor.enricher.YamlRollingTimeWindowMeanEnricher;
 import org.apache.brooklyn.sensor.enricher.YamlTimeWeightedDeltaEnricher;
 import org.apache.brooklyn.sensor.enricher.YamlRollingTimeWindowMeanEnricher.ConfidenceQualifiedNumber;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/sensor/enricher/YamlTimeWeightedDeltaEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/enricher/YamlTimeWeightedDeltaEnricherTest.java b/core/src/test/java/org/apache/brooklyn/sensor/enricher/YamlTimeWeightedDeltaEnricherTest.java
index 140ed15..5b98168 100644
--- a/core/src/test/java/org/apache/brooklyn/sensor/enricher/YamlTimeWeightedDeltaEnricherTest.java
+++ b/core/src/test/java/org/apache/brooklyn/sensor/enricher/YamlTimeWeightedDeltaEnricherTest.java
@@ -26,9 +26,9 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.EnricherSpec;
 import org.apache.brooklyn.core.entity.AbstractApplication;
 import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.BasicSensorEvent;
 import org.apache.brooklyn.entity.stock.BasicEntity;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
-import org.apache.brooklyn.sensor.core.BasicSensorEvent;
 import org.apache.brooklyn.sensor.enricher.YamlTimeWeightedDeltaEnricher;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/sensor/feed/ConfigToAttributesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/feed/ConfigToAttributesTest.java b/core/src/test/java/org/apache/brooklyn/sensor/feed/ConfigToAttributesTest.java
index 2dd5bc4..b82aecf 100644
--- a/core/src/test/java/org/apache/brooklyn/sensor/feed/ConfigToAttributesTest.java
+++ b/core/src/test/java/org/apache/brooklyn/sensor/feed/ConfigToAttributesTest.java
@@ -24,10 +24,10 @@ import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.TemplatedStringAttributeSensorAndConfigKey;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.core.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.sensor.core.TemplatedStringAttributeSensorAndConfigKey;
 import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/test/java/org/apache/brooklyn/sensor/feed/function/FunctionFeedTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/sensor/feed/function/FunctionFeedTest.java b/core/src/test/java/org/apache/brooklyn/sensor/feed/function/FunctionFeedTest.java
index fc1dc1d..71b44b8 100644
--- a/core/src/test/java/org/apache/brooklyn/sensor/feed/function/FunctionFeedTest.java
+++ b/core/src/test/java/org/apache/brooklyn/sensor/feed/function/FunctionFeedTest.java
@@ -38,9 +38,9 @@ import org.apache.brooklyn.api.sensor.SensorEvent;
 import org.apache.brooklyn.api.sensor.SensorEventListener;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.EntityInternal.FeedSupport;
+import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.sensor.core.Sensors;
 import org.apache.brooklyn.sensor.feed.function.FunctionFeed;
 import org.apache.brooklyn.sensor.feed.function.FunctionFeedTest;
 import org.apache.brooklyn.sensor.feed.function.FunctionPollConfig;