Merge remote-tracking branch 'aledsage/fix/IntegrationTests-20130124'

Fix conflicts in core/src/test/java/brooklyn/entity/basic/EffectorConcatenateTest
(converted to java in other pull request, adds destroyAll here)
diff --git a/core/src/main/java/brooklyn/entity/basic/Entities.java b/core/src/main/java/brooklyn/entity/basic/Entities.java
index 1fd549d..93d9d21 100644
--- a/core/src/main/java/brooklyn/entity/basic/Entities.java
+++ b/core/src/main/java/brooklyn/entity/basic/Entities.java
@@ -30,6 +30,7 @@
 import brooklyn.location.Location;
 import brooklyn.management.ManagementContext;
 import brooklyn.management.Task;
+import brooklyn.management.internal.AbstractManagementContext;
 import brooklyn.management.internal.EffectorUtils;
 import brooklyn.management.internal.LocalManagementContext;
 import brooklyn.policy.Policy;
@@ -401,6 +402,20 @@
         }
     }
 
+    /**
+     * stops, destroys, and unmanages the given application -- and terminates the mangaement context;
+     * does as many as are valid given the type and state
+     */
+    public static void destroyAll(Application app) {
+        if (isManaged(app)) {
+            ManagementContext managementContext = app.getManagementContext();
+            if (app instanceof Startable) Entities.invokeEffector((EntityLocal)app, app, Startable.STOP).getUnchecked();
+            if (app instanceof AbstractEntity) ((AbstractEntity)app).destroy();
+            if (managementContext instanceof AbstractManagementContext) ((AbstractManagementContext)managementContext).terminate();
+            unmanage(app);
+        }
+    }
+
     public static boolean isManaged(Entity e) {
         return ((AbstractEntity)e).getManagementSupport().isDeployed() && ((AbstractEntity)e).getManagementSupport().getManagementContext(true).isRunning();
     }
diff --git a/core/src/main/java/brooklyn/event/adapter/ConfigSensorAdapter.groovy b/core/src/main/java/brooklyn/event/adapter/ConfigSensorAdapter.groovy
index c9571ad..e2028b5 100644
--- a/core/src/main/java/brooklyn/event/adapter/ConfigSensorAdapter.groovy
+++ b/core/src/main/java/brooklyn/event/adapter/ConfigSensorAdapter.groovy
@@ -2,12 +2,17 @@
 
 import groovy.transform.InheritConstructors
 import brooklyn.entity.basic.EntityLocal
-import brooklyn.event.Sensor
-import brooklyn.event.basic.AttributeSensorAndConfigKey;
+import brooklyn.event.basic.AttributeSensorAndConfigKey
+import brooklyn.event.feed.ConfigToAttributes
 
 
-/** simple config adapter which, on registration, sets all config-attributes from config values */ 
+/** 
+ * Simple config adapter which, on registration, sets all config-attributes from config values
+ * 
+ * @deprecated since 0.5; use ConfigToAttributes instead
+ */ 
 @InheritConstructors
+@Deprecated
 public class ConfigSensorAdapter extends AbstractSensorAdapter {
 
     void register(SensorRegistry registry) {
@@ -21,17 +26,11 @@
 
     //normally just applied once, statically, not registered...
     public static void apply(EntityLocal entity) {
-        for (Sensor it : entity.getEntityType().getSensors()) {
-            if (it in AttributeSensorAndConfigKey && entity.getAttribute(it)==null) {
-                entity.setAttribute(it)
-            }
-        }
+        ConfigToAttributes.apply(entity);
     }
 
     //for selectively applying once (e.g. sub-classes of DynamicWebAppCluster that don't want to set HTTP_PORT etc!)
     public static void apply(EntityLocal entity, AttributeSensorAndConfigKey key) {
-        if (entity.getAttribute(key)==null) {
-            entity.setAttribute(key)
-        }
+        ConfigToAttributes.apply(entity, key);
     }
 }
diff --git a/core/src/main/java/brooklyn/event/basic/AttributeSensorAndConfigKey.java b/core/src/main/java/brooklyn/event/basic/AttributeSensorAndConfigKey.java
index b285e24..3bcbd1f 100644
--- a/core/src/main/java/brooklyn/event/basic/AttributeSensorAndConfigKey.java
+++ b/core/src/main/java/brooklyn/event/basic/AttributeSensorAndConfigKey.java
@@ -5,7 +5,7 @@
 import brooklyn.entity.basic.AbstractEntity;
 import brooklyn.entity.basic.EntityLocal;
 import brooklyn.event.Sensor;
-import brooklyn.event.adapter.ConfigSensorAdapter;
+import brooklyn.event.feed.ConfigToAttributes;
 import brooklyn.util.flags.TypeCoercions;
 
 /**
@@ -52,7 +52,7 @@
      * <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 convertConfigToSensor instead for single-execution calls.
      * the framework calls this from {@link AbstractEntity#setAttribute(AttributeSensorAndConfigKey)} 
-     * typically via {@link ConfigSensorAdapter#apply()} e.g. from SoftwareProcessEntity.preStart.)
+     * typically via {@link ConfigToAttributes#apply(EntityLocal)} e.g. from SoftwareProcessEntity.preStart.)
      * </b> 
      */
     public SensorType getAsSensorValue(Entity e) {
diff --git a/core/src/main/java/brooklyn/event/feed/ConfigToAttributes.java b/core/src/main/java/brooklyn/event/feed/ConfigToAttributes.java
new file mode 100644
index 0000000..42b687f
--- /dev/null
+++ b/core/src/main/java/brooklyn/event/feed/ConfigToAttributes.java
@@ -0,0 +1,27 @@
+package brooklyn.event.feed;
+
+import brooklyn.entity.basic.AbstractEntity;
+import brooklyn.entity.basic.EntityLocal;
+import brooklyn.event.Sensor;
+import brooklyn.event.basic.AttributeSensorAndConfigKey;
+
+
+/** simple config adapter for setting config-attributes from config values */ 
+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);
+            }
+        }
+    }
+
+    //for selectively applying once (e.g. sub-classes of DynamicWebAppCluster that don't want to set HTTP_PORT etc!)
+    public static void apply(EntityLocal entity, AttributeSensorAndConfigKey<?,?> key) {
+        if (entity.getAttribute(key)==null) {
+            ((AbstractEntity)entity).setAttribute((AttributeSensorAndConfigKey<?,?>)key);
+        }
+    }
+}
diff --git a/core/src/main/java/brooklyn/location/basic/jclouds/JcloudsUtil.java b/core/src/main/java/brooklyn/location/basic/jclouds/JcloudsUtil.java
index 45ba591..04435db 100644
--- a/core/src/main/java/brooklyn/location/basic/jclouds/JcloudsUtil.java
+++ b/core/src/main/java/brooklyn/location/basic/jclouds/JcloudsUtil.java
@@ -283,6 +283,7 @@
         //   For validating result, could use guava's InternetDomainName.isValidLenient(ip) or InetAddresses.isInetAddress(ip)
         //   He also mentioned context.utils.sshForNode
 
+        // TODO Inefficient code; should re-use executor
         Timeouts timeouts = new ComputeServiceConstants.Timeouts();
         ExecutorService executor = Executors.newCachedThreadPool();
         try {
diff --git a/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java b/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java
index 224fda1..416e62f 100644
--- a/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java
+++ b/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java
@@ -30,7 +30,8 @@
     private SubscriptionManager subscriptions;
     private LocalEntityManager entityManager;
     
-    private final String tostring = "LocalManagementContext("+Identifiers.getBase64IdFromValue(System.identityHashCode(this), 5)+")";
+    private final String shortid = Identifiers.getBase64IdFromValue(System.identityHashCode(this), 5);
+    private final String tostring = "LocalManagementContext("+shortid+")";
 
     /**
      * Creates a LocalManagement with default BrooklynProperties.
@@ -87,7 +88,7 @@
         if (!isRunning()) throw new IllegalStateException("Management context no longer running");
         
         if (execution == null) {
-            execution = new BasicExecutionManager();
+            execution = new BasicExecutionManager(shortid);
             gc = new BrooklynGarbageCollector(configMap, execution);
         }
         return execution;
diff --git a/core/src/main/java/brooklyn/util/task/BasicExecutionManager.java b/core/src/main/java/brooklyn/util/task/BasicExecutionManager.java
index d9f92e1..1c533e3 100644
--- a/core/src/main/java/brooklyn/util/task/BasicExecutionManager.java
+++ b/core/src/main/java/brooklyn/util/task/BasicExecutionManager.java
@@ -17,7 +17,6 @@
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
@@ -37,6 +36,7 @@
 
 import com.google.common.base.CaseFormat;
 import com.google.common.base.Throwables;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
 
 /**
  * TODO javadoc
@@ -83,20 +83,13 @@
         return Tasks.withBlockingDetails(description, code);
     }
 
-    private ThreadFactory threadFactory = newThreadFactory();
-    private ThreadFactory daemonThreadFactory = new ThreadFactory() {
-        public Thread newThread(Runnable r) {
-            Thread t = threadFactory.newThread(r); 
-            t.setDaemon(true); 
-            return t;
-        }
-    };
+    private final ThreadFactory threadFactory;
     
-    private ExecutorService runner = 
-		new ThreadPoolExecutor(0, Integer.MAX_VALUE, 1L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), daemonThreadFactory);
-//      above is Executors.newCachedThreadPool(daemonThreadFactory)  but timeout of 1s rather than 60s for better shutdown!
+    private final ThreadFactory daemonThreadFactory;
+    
+    private final ExecutorService runner;
         
-	private ScheduledExecutorService delayedRunner = new ScheduledThreadPoolExecutor(1, daemonThreadFactory);
+	private final ScheduledExecutorService delayedRunner;
 	
     // TODO Could have a set of all knownTasks; but instead we're having a separate set per tag,
     // so the same task could be listed multiple times if it has multiple tags...
@@ -105,12 +98,12 @@
     //(but more testing is needed before we are sure it is thread-safe!)
     //synch blocks are as finely grained as possible for efficiency
     //Not using a CopyOnWriteArraySet for each, because profiling showed this being a massive perf bottleneck.
-    private ConcurrentMap<Object,Set<Task>> tasksByTag = new ConcurrentHashMap();
+    private ConcurrentMap<Object,Set<Task>> tasksByTag = new ConcurrentHashMap<Object,Set<Task>>();
 
     @Deprecated
-    private ConcurrentMap<Object, TaskPreprocessor> preprocessorByTag = new ConcurrentHashMap();
+    private ConcurrentMap<Object, TaskPreprocessor> preprocessorByTag = new ConcurrentHashMap<Object, TaskPreprocessor>();
 
-    private ConcurrentMap<Object, TaskScheduler> schedulerByTag = new ConcurrentHashMap();
+    private ConcurrentMap<Object, TaskScheduler> schedulerByTag = new ConcurrentHashMap<Object, TaskScheduler>();
     
     private final AtomicLong totalTaskCount = new AtomicLong();
     
@@ -120,9 +113,34 @@
     
     private final List<ExecutionListener> listeners = new CopyOnWriteArrayList<ExecutionListener>();
     
-	/** for use by overriders to use custom thread factory */
-	protected ThreadFactory newThreadFactory() {
-		return Executors.defaultThreadFactory();
+    public BasicExecutionManager(String contextid) {
+        threadFactory = newThreadFactory(contextid);
+        daemonThreadFactory = new ThreadFactoryBuilder()
+                .setThreadFactory(threadFactory)
+                .setDaemon(true)
+                .build();
+                
+        // use Executors.newCachedThreadPool(daemonThreadFactory), but timeout of 1s rather than 60s for better shutdown!
+        runner = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 1L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), 
+                daemonThreadFactory);
+            
+        delayedRunner = new ScheduledThreadPoolExecutor(1, daemonThreadFactory);
+    }
+    
+	/** 
+	 * For use by overriders to use custom thread factory.
+	 * But be extremely careful: called by constructor, so before sub-class' constructor will
+	 * have been invoked!
+	 */
+	protected ThreadFactory newThreadFactory(String contextid) {
+	    return new ThreadFactoryBuilder()
+        	    .setNameFormat("brooklyn-execmanager-"+contextid+"-%d")
+        	    .setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler(){
+                        @Override
+                        public void uncaughtException(Thread t, Throwable e) {
+                            log.error("Uncaught exception in thread "+t.getName(), e);
+                        }})
+                .build();
 	}
 	
     public void shutdownNow() {
diff --git a/core/src/test/java/brooklyn/enricher/CombiningEnricherTest.groovy b/core/src/test/java/brooklyn/enricher/CombiningEnricherTest.groovy
index 5fb3d29..e5177d9 100644
--- a/core/src/test/java/brooklyn/enricher/CombiningEnricherTest.groovy
+++ b/core/src/test/java/brooklyn/enricher/CombiningEnricherTest.groovy
@@ -45,7 +45,7 @@
     
     @AfterMethod(alwaysRun=true)
     public void after() {
-        if (app!=null) Entities.destroy(app);
+        if (app!=null) Entities.destroyAll(app);
     }
     
     @Test
diff --git a/core/src/test/java/brooklyn/enricher/TransformingEnricherTest.groovy b/core/src/test/java/brooklyn/enricher/TransformingEnricherTest.groovy
index 821e048..a503cd5 100644
--- a/core/src/test/java/brooklyn/enricher/TransformingEnricherTest.groovy
+++ b/core/src/test/java/brooklyn/enricher/TransformingEnricherTest.groovy
@@ -47,7 +47,7 @@
     
     @AfterMethod(alwaysRun=true)
     public void after() {
-        if (app!=null) Entities.destroy(app);
+        if (app!=null) Entities.destroyAll(app);
     }
     
     @Test
diff --git a/core/src/test/java/brooklyn/entity/EffectorSayHiTest.groovy b/core/src/test/java/brooklyn/entity/EffectorSayHiTest.groovy
index df6dcad..b6dbf5a 100644
--- a/core/src/test/java/brooklyn/entity/EffectorSayHiTest.groovy
+++ b/core/src/test/java/brooklyn/entity/EffectorSayHiTest.groovy
@@ -42,7 +42,7 @@
     
     @AfterMethod(alwaysRun=true)
     public void tearDown() {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
     
     @Test
diff --git a/core/src/test/java/brooklyn/entity/basic/AbstractApplicationTest.groovy b/core/src/test/java/brooklyn/entity/basic/AbstractApplicationTest.groovy
index ddb34e1..3a3a190 100644
--- a/core/src/test/java/brooklyn/entity/basic/AbstractApplicationTest.groovy
+++ b/core/src/test/java/brooklyn/entity/basic/AbstractApplicationTest.groovy
@@ -20,7 +20,7 @@
     
     @AfterMethod(alwaysRun=true)
     public void tearDown() throws Exception {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
     
     // App and its children will be implicitly managed on first effector call on app
diff --git a/core/src/test/java/brooklyn/entity/basic/AttributeMapTest.groovy b/core/src/test/java/brooklyn/entity/basic/AttributeMapTest.groovy
index 0d44b5c..2ac1c55 100644
--- a/core/src/test/java/brooklyn/entity/basic/AttributeMapTest.groovy
+++ b/core/src/test/java/brooklyn/entity/basic/AttributeMapTest.groovy
@@ -32,7 +32,7 @@
     
     @AfterMethod(alwaysRun=true)
     public void tearDown() {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
     
     // See ENGR-2111
diff --git a/core/src/test/java/brooklyn/entity/basic/DynamicGroupTest.groovy b/core/src/test/java/brooklyn/entity/basic/DynamicGroupTest.groovy
index 127fc87..4190438 100644
--- a/core/src/test/java/brooklyn/entity/basic/DynamicGroupTest.groovy
+++ b/core/src/test/java/brooklyn/entity/basic/DynamicGroupTest.groovy
@@ -49,7 +49,7 @@
     
     @AfterMethod(alwaysRun=true)
     public void tearDown() throws Exception {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
     
     @Test
diff --git a/core/src/test/java/brooklyn/entity/basic/EffectorConcatenateTest.java b/core/src/test/java/brooklyn/entity/basic/EffectorConcatenateTest.java
index 1350a93..3d8732f 100644
--- a/core/src/test/java/brooklyn/entity/basic/EffectorConcatenateTest.java
+++ b/core/src/test/java/brooklyn/entity/basic/EffectorConcatenateTest.java
@@ -109,7 +109,7 @@
     
     @AfterMethod(alwaysRun=true)
     public void tearDown() {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
     
     @Test
diff --git a/core/src/test/java/brooklyn/entity/basic/EntitySubscriptionTest.groovy b/core/src/test/java/brooklyn/entity/basic/EntitySubscriptionTest.groovy
index 9feaf61..ab212e6 100644
--- a/core/src/test/java/brooklyn/entity/basic/EntitySubscriptionTest.groovy
+++ b/core/src/test/java/brooklyn/entity/basic/EntitySubscriptionTest.groovy
@@ -56,7 +56,7 @@
     
     @AfterMethod(alwaysRun=true)
     public void tearDown() {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
     
     @Test
diff --git a/core/src/test/java/brooklyn/event/adapter/HttpSensorAdapterTest.groovy b/core/src/test/java/brooklyn/event/adapter/HttpSensorAdapterTest.groovy
index bfeb5a0..96234cf 100644
--- a/core/src/test/java/brooklyn/event/adapter/HttpSensorAdapterTest.groovy
+++ b/core/src/test/java/brooklyn/event/adapter/HttpSensorAdapterTest.groovy
@@ -39,7 +39,7 @@
     @AfterMethod(alwaysRun=true)
     public void tearDown() throws Exception {
         if (registry != null) registry.close();
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
 
 	@Test
diff --git a/core/src/test/java/brooklyn/event/adapter/ShellSensorAdapterTest.groovy b/core/src/test/java/brooklyn/event/adapter/ShellSensorAdapterTest.groovy
index 79746cb..e87f4c1 100644
--- a/core/src/test/java/brooklyn/event/adapter/ShellSensorAdapterTest.groovy
+++ b/core/src/test/java/brooklyn/event/adapter/ShellSensorAdapterTest.groovy
@@ -31,7 +31,7 @@
     
     @AfterMethod(alwaysRun=true)
     public void tearDown() throws Exception {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
     
     ShellSensorAdapter adapter;
diff --git a/core/src/test/java/brooklyn/event/adapter/SshSensorAdapterTest.groovy b/core/src/test/java/brooklyn/event/adapter/SshSensorAdapterTest.groovy
index 1523a27..5851932 100644
--- a/core/src/test/java/brooklyn/event/adapter/SshSensorAdapterTest.groovy
+++ b/core/src/test/java/brooklyn/event/adapter/SshSensorAdapterTest.groovy
@@ -40,7 +40,7 @@
 
     @AfterClass(alwaysRun=true)
     public void tearDown() {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
 
 	@Test
diff --git a/core/src/test/java/brooklyn/event/feed/function/FunctionFeedTest.java b/core/src/test/java/brooklyn/event/feed/function/FunctionFeedTest.java
index 32f6dbf..9052fea 100644
--- a/core/src/test/java/brooklyn/event/feed/function/FunctionFeedTest.java
+++ b/core/src/test/java/brooklyn/event/feed/function/FunctionFeedTest.java
@@ -53,7 +53,7 @@
     @AfterMethod(alwaysRun=true)
     public void tearDown() throws Exception {
         if (feed != null) feed.stop();
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
     
     @Test
diff --git a/core/src/test/java/brooklyn/event/feed/http/HttpFeedSslIntegrationTest.java b/core/src/test/java/brooklyn/event/feed/http/HttpFeedSslIntegrationTest.java
index f644aca..f636456 100644
--- a/core/src/test/java/brooklyn/event/feed/http/HttpFeedSslIntegrationTest.java
+++ b/core/src/test/java/brooklyn/event/feed/http/HttpFeedSslIntegrationTest.java
@@ -55,7 +55,7 @@
     public void tearDown() throws Exception {
         if (feed != null) feed.stop();
         if (httpService != null) httpService.shutdown();
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
     
     @Test
diff --git a/core/src/test/java/brooklyn/event/feed/http/HttpFeedTest.java b/core/src/test/java/brooklyn/event/feed/http/HttpFeedTest.java
index 04066f3..42d6984 100644
--- a/core/src/test/java/brooklyn/event/feed/http/HttpFeedTest.java
+++ b/core/src/test/java/brooklyn/event/feed/http/HttpFeedTest.java
@@ -60,7 +60,7 @@
     public void tearDown() throws Exception {
         if (feed != null) feed.stop();
         if (server != null) server.shutdown();
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
         feed = null;
     }
     
diff --git a/core/src/test/java/brooklyn/event/feed/shell/ShellFeedIntegrationTest.java b/core/src/test/java/brooklyn/event/feed/shell/ShellFeedIntegrationTest.java
index 1bd4847..1bdf7ab 100644
--- a/core/src/test/java/brooklyn/event/feed/shell/ShellFeedIntegrationTest.java
+++ b/core/src/test/java/brooklyn/event/feed/shell/ShellFeedIntegrationTest.java
@@ -50,7 +50,7 @@
     @AfterMethod(alwaysRun=true)
     public void tearDown() throws Exception {
         if (feed != null) feed.stop();
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
         if (loc != null) Closeables.closeQuietly(loc);
     }
     
diff --git a/core/src/test/java/brooklyn/event/feed/ssh/SshFeedIntegrationTest.java b/core/src/test/java/brooklyn/event/feed/ssh/SshFeedIntegrationTest.java
index 678f289..56b0cf6 100644
--- a/core/src/test/java/brooklyn/event/feed/ssh/SshFeedIntegrationTest.java
+++ b/core/src/test/java/brooklyn/event/feed/ssh/SshFeedIntegrationTest.java
@@ -45,7 +45,7 @@
     @AfterMethod(alwaysRun=true)
     public void tearDown() throws Exception {
         if (feed != null) feed.stop();
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
         if (loc != null) Closeables.closeQuietly(loc);
     }
     
diff --git a/core/src/test/java/brooklyn/injava/JavaEnricherTest.java b/core/src/test/java/brooklyn/injava/JavaEnricherTest.java
index c7c5da8..8943191 100644
--- a/core/src/test/java/brooklyn/injava/JavaEnricherTest.java
+++ b/core/src/test/java/brooklyn/injava/JavaEnricherTest.java
@@ -31,7 +31,7 @@
     
     @AfterMethod(alwaysRun=true)
     public void tearDown() throws Exception {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
     
     @Test
diff --git a/core/src/test/java/brooklyn/injava/JavaEntityTest.java b/core/src/test/java/brooklyn/injava/JavaEntityTest.java
index 4e14aac..820eaca 100644
--- a/core/src/test/java/brooklyn/injava/JavaEntityTest.java
+++ b/core/src/test/java/brooklyn/injava/JavaEntityTest.java
@@ -32,13 +32,15 @@
     
     @AfterMethod(alwaysRun=true)
     public void tearDown() throws Exception {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
     
     @Test
     public void testPolicySubscribesToEvents() {
         final ExampleJavaPolicy policy = new ExampleJavaPolicy();
+        entity = new ExampleJavaEntity(MutableMap.of("displayName", "myName", "myConfig1", "myVal1"), app);
         entity.addPolicy(policy);
+        Entities.manage(entity);
         
         entity.setAttribute(ExampleJavaEntity.MY_SENSOR1, "val1");
         
diff --git a/core/src/test/java/brooklyn/injava/JavaPolicyTest.java b/core/src/test/java/brooklyn/injava/JavaPolicyTest.java
index 162ebf8..513ff1e 100644
--- a/core/src/test/java/brooklyn/injava/JavaPolicyTest.java
+++ b/core/src/test/java/brooklyn/injava/JavaPolicyTest.java
@@ -31,7 +31,7 @@
     
     @AfterMethod(alwaysRun=true)
     public void tearDown() throws Exception {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
     
     @Test
diff --git a/core/src/test/java/brooklyn/management/internal/EntityExecutionManagerTest.groovy b/core/src/test/java/brooklyn/management/internal/EntityExecutionManagerTest.groovy
index 772dfea..698a3fc 100644
--- a/core/src/test/java/brooklyn/management/internal/EntityExecutionManagerTest.groovy
+++ b/core/src/test/java/brooklyn/management/internal/EntityExecutionManagerTest.groovy
@@ -40,7 +40,7 @@
     
     @AfterMethod(alwaysRun=true)
     public void tearDown() throws Exception {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
 
     @Test
diff --git a/core/src/test/java/brooklyn/qa/performance/AbstractPerformanceTest.java b/core/src/test/java/brooklyn/qa/performance/AbstractPerformanceTest.java
index 04cceb7..be7a79e 100644
--- a/core/src/test/java/brooklyn/qa/performance/AbstractPerformanceTest.java
+++ b/core/src/test/java/brooklyn/qa/performance/AbstractPerformanceTest.java
@@ -55,7 +55,7 @@
     
     @AfterMethod(alwaysRun=true)
     public void tearDown() {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
     
     protected void measureAndAssert(String prefix, int numIterations, double minRatePerSec, Runnable r) {
diff --git a/core/src/test/java/brooklyn/util/internal/SensorRegistryTest.groovy b/core/src/test/java/brooklyn/util/internal/SensorRegistryTest.groovy
index f4a3da3..dcdcef3 100644
--- a/core/src/test/java/brooklyn/util/internal/SensorRegistryTest.groovy
+++ b/core/src/test/java/brooklyn/util/internal/SensorRegistryTest.groovy
@@ -41,7 +41,7 @@
     
     @AfterMethod(alwaysRun=true)
     public void tearDown() {
-        if (app != null) Entities.destroy(app)
+        if (app != null) Entities.destroyAll(app)
     }
     
     @Test
diff --git a/policy/src/main/java/brooklyn/entity/brooklyn/BrooklynMetrics.groovy b/policy/src/main/java/brooklyn/entity/brooklyn/BrooklynMetrics.groovy
index 70185af..1e7ff3d 100644
--- a/policy/src/main/java/brooklyn/entity/brooklyn/BrooklynMetrics.groovy
+++ b/policy/src/main/java/brooklyn/entity/brooklyn/BrooklynMetrics.groovy
@@ -2,6 +2,7 @@
 
 import java.util.concurrent.Executors
 import java.util.concurrent.ScheduledExecutorService
+import java.util.concurrent.ThreadFactory
 import java.util.concurrent.TimeUnit
 
 import brooklyn.entity.Entity
@@ -13,6 +14,8 @@
 import brooklyn.util.flags.SetFromFlag
 import brooklyn.util.task.BasicExecutionManager
 
+import com.google.common.util.concurrent.ThreadFactoryBuilder
+
 public class BrooklynMetrics extends AbstractEntity {
 
     @SetFromFlag("updatePeriod")
@@ -39,7 +42,11 @@
     }
     
     public void onManagementBecomingMaster() {
-        executor = Executors.newSingleThreadScheduledExecutor()
+        // TODO Don't use own thread pool; use new "feeds" (see FunctionFeed, or variants there of)
+        ThreadFactory threadFactory = new ThreadFactoryBuilder()
+                .setNameFormat("brooklyn-brooklynmetrics-poller-%d")
+                .build();
+        executor = Executors.newSingleThreadScheduledExecutor(threadFactory)
         executor.scheduleWithFixedDelay(
                 { refreshSensors() }, 
                 0, 
diff --git a/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java b/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java
index e16c404..965419c 100644
--- a/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java
+++ b/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java
@@ -9,6 +9,7 @@
 import java.util.Map;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -35,6 +36,7 @@
 import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Throwables;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
 
 
 /**
@@ -225,9 +227,9 @@
     
     private Entity poolEntity;
     
-    private volatile ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
     private final AtomicBoolean executorQueued = new AtomicBoolean(false);
     private volatile long executorTime = 0;
+    private volatile ScheduledExecutorService executor;
     
     private final TimeWindowedList<Number> recentDesiredResizes;
     
@@ -281,6 +283,9 @@
         
         long maxResizeStabilizationDelay = Math.max(resizeUpStabilizationDelay, resizeDownStabilizationDelay);
         recentDesiredResizes = new TimeWindowedList<Number>(MutableMap.of("timePeriod", maxResizeStabilizationDelay, "minExpiredVals", 1));
+        
+        // TODO Should re-use the execution manager's thread pool, somehow
+        executor = Executors.newSingleThreadScheduledExecutor(newThreadFactory());
     }
 
     public void setMetricLowerBound(Number val) {
@@ -328,7 +333,7 @@
     @Override
     public void resume() {
         super.resume();
-        executor = Executors.newSingleThreadScheduledExecutor();
+        executor = Executors.newSingleThreadScheduledExecutor(newThreadFactory());
     }
     
     @Override
@@ -348,6 +353,12 @@
         subscribe(poolEntity, poolOkSensor, utilizationEventHandler);
     }
     
+    private ThreadFactory newThreadFactory() {
+        return new ThreadFactoryBuilder()
+                .setNameFormat("brooklyn-autoscalerpolicy-%d")
+                .build();
+    }
+    
     private void onMetricChanged(Number val) {
         if (LOG.isTraceEnabled()) LOG.trace("{} recording pool-metric for {}: {}", new Object[] {this, poolEntity, val});
 
diff --git a/policy/src/main/java/brooklyn/policy/followthesun/FollowTheSunPolicy.java b/policy/src/main/java/brooklyn/policy/followthesun/FollowTheSunPolicy.java
index a774de8..be4b0b7 100644
--- a/policy/src/main/java/brooklyn/policy/followthesun/FollowTheSunPolicy.java
+++ b/policy/src/main/java/brooklyn/policy/followthesun/FollowTheSunPolicy.java
@@ -8,6 +8,7 @@
 import java.util.Map;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -31,6 +32,7 @@
 
 import com.google.common.base.Function;
 import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
 
 public class FollowTheSunPolicy extends AbstractPolicy {
 
@@ -51,7 +53,7 @@
     
     private FollowTheSunPool poolEntity;
     
-    private volatile ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
+    private volatile ScheduledExecutorService executor;
     private final AtomicBoolean executorQueued = new AtomicBoolean(false);
     private volatile long executorTime = 0;
     private boolean loggedConstraintsIgnored = false;
@@ -109,6 +111,9 @@
         this.parameters = parameters;
         this.strategy = new FollowTheSunStrategy<Entity, Movable>(model, parameters); // TODO: extract interface, inject impl
         this.locationFinder = elvis(locationFinder, defaultLocationFinder);
+        
+        // TODO Should re-use the execution manager's thread pool, somehow
+        executor = Executors.newSingleThreadScheduledExecutor(newThreadFactory());
     }
     
     @Override
@@ -146,11 +151,17 @@
     @Override
     public void resume() {
         super.resume();
-        executor = Executors.newSingleThreadScheduledExecutor();
+        executor = Executors.newSingleThreadScheduledExecutor(newThreadFactory());
         executorTime = 0;
         executorQueued.set(false);
     }
     
+    private ThreadFactory newThreadFactory() {
+        return new ThreadFactoryBuilder()
+                .setNameFormat("brooklyn-followthesunpolicy-%d")
+                .build();
+    }
+
     private void scheduleLatencyReductionJig() {
         if (isRunning() && executorQueued.compareAndSet(false, true)) {
             long now = System.currentTimeMillis();
diff --git a/policy/src/main/java/brooklyn/policy/loadbalancing/LoadBalancingPolicy.java b/policy/src/main/java/brooklyn/policy/loadbalancing/LoadBalancingPolicy.java
index a3ffb86..0677213 100644
--- a/policy/src/main/java/brooklyn/policy/loadbalancing/LoadBalancingPolicy.java
+++ b/policy/src/main/java/brooklyn/policy/loadbalancing/LoadBalancingPolicy.java
@@ -7,6 +7,7 @@
 import java.util.Map.Entry;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -29,6 +30,7 @@
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
 
 
 /**
@@ -60,7 +62,7 @@
     private final BalancingStrategy<NodeType, ItemType> strategy;
     private BalanceableWorkerPool poolEntity;
     
-    private volatile ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
+    private volatile ScheduledExecutorService executor;
     private final AtomicBoolean executorQueued = new AtomicBoolean(false);
     private volatile long executorTime = 0;
 
@@ -106,6 +108,9 @@
         this.highThresholdConfigKeyName = metric.getName()+".threshold.high";
         this.model = model;
         this.strategy = new BalancingStrategy(getName(), model); // TODO: extract interface, inject impl
+        
+        // TODO Should re-use the execution manager's thread pool, somehow
+        executor = Executors.newSingleThreadScheduledExecutor(newThreadFactory());
     }
     
     @Override
@@ -143,11 +148,17 @@
     @Override
     public void resume() {
         super.resume();
-        executor = Executors.newSingleThreadScheduledExecutor();
+        executor = Executors.newSingleThreadScheduledExecutor(newThreadFactory());
         executorTime = 0;
         executorQueued.set(false);
     }
     
+    private ThreadFactory newThreadFactory() {
+        return new ThreadFactoryBuilder()
+                .setNameFormat("brooklyn-followthesunpolicy-%d")
+                .build();
+    }
+
     private void scheduleRebalance() {
         if (isRunning() && executorQueued.compareAndSet(false, true)) {
             long now = System.currentTimeMillis();
diff --git a/policy/src/test/java/brooklyn/enricher/TimeFractionDeltaEnricherTest.java b/policy/src/test/java/brooklyn/enricher/TimeFractionDeltaEnricherTest.java
index 9c0f21e..b8127ea 100644
--- a/policy/src/test/java/brooklyn/enricher/TimeFractionDeltaEnricherTest.java
+++ b/policy/src/test/java/brooklyn/enricher/TimeFractionDeltaEnricherTest.java
@@ -42,7 +42,7 @@
 
     @AfterMethod(alwaysRun=true)
     public void after() {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
 
     @Test
diff --git a/policy/src/test/java/brooklyn/policy/autoscaling/AutoScalerPolicyTest.java b/policy/src/test/java/brooklyn/policy/autoscaling/AutoScalerPolicyTest.java
index ec4d96f..1fc4342 100644
--- a/policy/src/test/java/brooklyn/policy/autoscaling/AutoScalerPolicyTest.java
+++ b/policy/src/test/java/brooklyn/policy/autoscaling/AutoScalerPolicyTest.java
@@ -9,10 +9,12 @@
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import brooklyn.entity.Entity;
+import brooklyn.entity.basic.Entities;
 import brooklyn.entity.trait.Resizable;
 import brooklyn.event.basic.BasicNotificationSensor;
 import brooklyn.test.entity.TestApplication;
@@ -28,7 +30,7 @@
 
     static { TimeExtras.init(); }
 
-    private static long TIMEOUT_MS = 10000;
+    private static long TIMEOUT_MS = 10*1000;
     private static long SHORT_WAIT_MS = 250;
     private static long OVERHEAD_DURATION_MS = 500;
     private static long EARLY_RETURN_MS = 10;
@@ -36,10 +38,11 @@
     AutoScalerPolicy policy;
     TestCluster cluster;
     LocallyResizableEntity resizable;
+    TestApplication app;
     
     @BeforeMethod(alwaysRun=true)
-    public void before() throws Exception {
-        TestApplication app = new TestApplication();
+    public void setUp() throws Exception {
+        app = new TestApplication();
         cluster = new TestCluster(app, 1);
         resizable = new LocallyResizableEntity(cluster, cluster);
         policy = new AutoScalerPolicy();
@@ -48,6 +51,15 @@
         app.startManagement();
     }
 
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (policy != null) policy.destroy();
+        if (app != null) Entities.destroyAll(app);
+        cluster = null;
+        resizable = null;
+        policy = null;
+    }
+
     @Test
     public void testShrinkColdPool() throws Exception {
         resizable.resize(4);
@@ -297,8 +309,7 @@
         resizable.emit(AutoScalerPolicy.POOL_HOT, message(1, 21L, 1*10L, 1*20L)); // would grow to 2
         Thread.sleep(resizeUpStabilizationDelay-OVERHEAD_DURATION_MS);
         
-        Stopwatch stopwatch2 = new Stopwatch();
-        stopwatch2.start();
+        long postSleepTime = stopwatch.elapsedMillis();
         
         resizable.emit(AutoScalerPolicy.POOL_HOT, message(1, 61L, 1*10L, 1*20L)); // would grow to 4
 
@@ -310,23 +321,21 @@
                 assertTrue(resizable.getCurrentSize() >= 2, "currentSize="+resizable.getCurrentSize());
             }});
         assertEquals(resizable.getCurrentSize(), (Integer)2, 
-                stopwatch.elapsedMillis()+"ms after first emission; "+stopwatch2.elapsedMillis()+"ms after last");
+                stopwatch.elapsedMillis()+"ms after first emission; "+(stopwatch.elapsedMillis()-postSleepTime)+"ms after last");
         
-        long timeToResize = stopwatch.elapsedMillis();
-        assertTrue(timeToResize >= resizeUpStabilizationDelay-EARLY_RETURN_MS &&
-                timeToResize <= resizeUpStabilizationDelay+OVERHEAD_DURATION_MS,
-                "Resizing to 2: time="+timeToResize+"; resizeUpStabilizationDelay="+resizeUpStabilizationDelay);
+        long timeToResizeTo2 = stopwatch.elapsedMillis();
+        assertTrue(timeToResizeTo2 >= resizeUpStabilizationDelay-EARLY_RETURN_MS &&
+                timeToResizeTo2 <= resizeUpStabilizationDelay+OVERHEAD_DURATION_MS,
+                "Resizing to 2: time="+timeToResizeTo2+"; resizeUpStabilizationDelay="+resizeUpStabilizationDelay);
 
         // Will then grow to 4 $resizeUpStabilizationDelay milliseconds after that emission
-        executeUntilSucceeds(MutableMap.of("period", 1, "timeout", TIMEOUT_MS), new Runnable() {
-                public void run() { 
-                    assertEquals(resizable.getCurrentSize(), (Integer)4);
-                }});
-        long timeToResizeTo4 = stopwatch2.elapsedMillis();
+        executeUntilSucceeds(MutableMap.of("period", 1, "timeout", TIMEOUT_MS), 
+                currentSizeAsserter(resizable, 4));
+        long timeToResizeTo4 = stopwatch.elapsedMillis() - postSleepTime;
         
         assertTrue(timeToResizeTo4 >= resizeUpStabilizationDelay-EARLY_RETURN_MS &&
                 timeToResizeTo4 <= resizeUpStabilizationDelay+OVERHEAD_DURATION_MS,
-                "Resizing to 4: time="+timeToResize+"; resizeUpStabilizationDelay="+resizeUpStabilizationDelay);
+                "Resizing to 4: timeToResizeTo4="+timeToResizeTo4+"; timeToResizeTo2="+timeToResizeTo2+"; resizeUpStabilizationDelay="+resizeUpStabilizationDelay);
     }
 
     @Test(groups="Integration")
@@ -415,31 +424,33 @@
         resizable.emit(AutoScalerPolicy.POOL_COLD, message(3, 20L, 3*10L, 3*20L)); // would shrink to 2
         Thread.sleep(resizeDownStabilizationDelay-OVERHEAD_DURATION_MS);
         
-        Stopwatch stopwatch2 = new Stopwatch();
-        stopwatch2.start();
+        long postSleepTime = stopwatch.elapsedMillis();
         
         resizable.emit(AutoScalerPolicy.POOL_COLD, message(3, 1L, 3*10L, 3*20L)); // would shrink to 1
 
-        // Wait for it to shrink to size 2, and confirm take expected time
-        executeUntilSucceeds(MutableMap.of("period", 1, "timeout", TIMEOUT_MS),
-                currentSizeAsserter(resizable, 2));
+        // Wait for it to reach size 2, and confirm take expected time
+        // TODO This is time sensitive, and sometimes fails in CI with size=1 if we wait for currentSize==2 (presumably GC kicking in?)
+        //      Therefore do strong assertion of currentSize==2 later, so can write out times if it goes wrong.
+        executeUntilSucceeds(MutableMap.of("period", 1, "timeout", TIMEOUT_MS), new Runnable() {
+                public void run() {
+                    assertTrue(resizable.getCurrentSize() <= 2, "currentSize="+resizable.getCurrentSize());
+                }});
+        assertEquals(resizable.getCurrentSize(), (Integer)2, 
+                stopwatch.elapsedMillis()+"ms after first emission; "+(stopwatch.elapsedMillis()-postSleepTime)+"ms after last");
         
-        long timeToResize = stopwatch.elapsedMillis();
-        assertTrue(timeToResize >= resizeDownStabilizationDelay-EARLY_RETURN_MS &&
-                timeToResize <= resizeDownStabilizationDelay+OVERHEAD_DURATION_MS,
-                "Resizing to 2: time="+timeToResize+"; resizeDownStabilizationDelay="+resizeDownStabilizationDelay);
+        long timeToResizeTo2 = stopwatch.elapsedMillis();
+        assertTrue(timeToResizeTo2 >= resizeDownStabilizationDelay-EARLY_RETURN_MS &&
+                timeToResizeTo2 <= resizeDownStabilizationDelay+OVERHEAD_DURATION_MS,
+                "Resizing to 2: time="+timeToResizeTo2+"; resizeDownStabilizationDelay="+resizeDownStabilizationDelay);
 
         // Will then shrink to 1 $resizeUpStabilizationDelay milliseconds after that emission
-        executeUntilSucceeds(MutableMap.of("period", 1, "timeout", TIMEOUT_MS), new Runnable() {
-                @Override public void run() {
-                    assertEquals(resizable.getCurrentSize(), (Integer)1);
-                }});
-        long timeToResizeTo1 = stopwatch2.elapsedMillis();
+        executeUntilSucceeds(MutableMap.of("period", 1, "timeout", TIMEOUT_MS), 
+                currentSizeAsserter(resizable, 1));
+        long timeToResizeTo1 = stopwatch.elapsedMillis() - postSleepTime;
         
         assertTrue(timeToResizeTo1 >= resizeDownStabilizationDelay-EARLY_RETURN_MS &&
                 timeToResizeTo1 <= resizeDownStabilizationDelay+OVERHEAD_DURATION_MS,
-                "Resizing to 1: time="+timeToResize+"; resizeDownStabilizationDelay="+resizeDownStabilizationDelay);
-
+                "Resizing to 1: timeToResizeTo1="+timeToResizeTo1+"; timeToResizeTo2="+timeToResizeTo2+"; resizeDownStabilizationDelay="+resizeDownStabilizationDelay);
     }
 
     @Test(groups="Integration")
diff --git a/policy/src/test/java/brooklyn/policy/followthesun/AbstractFollowTheSunPolicyTest.groovy b/policy/src/test/java/brooklyn/policy/followthesun/AbstractFollowTheSunPolicyTest.groovy
index fe55bb3..e2bd6f2 100644
--- a/policy/src/test/java/brooklyn/policy/followthesun/AbstractFollowTheSunPolicyTest.groovy
+++ b/policy/src/test/java/brooklyn/policy/followthesun/AbstractFollowTheSunPolicyTest.groovy
@@ -69,7 +69,7 @@
     @AfterMethod(alwaysRun=true)
     public void after() {
         if (pool != null && policy != null) pool.removePolicy(policy)
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
         MockItemEntity.totalMoveCount.set(0)
     }
     
diff --git a/policy/src/test/java/brooklyn/policy/ha/MemberFailureDetectionPolicyTest.java b/policy/src/test/java/brooklyn/policy/ha/MemberFailureDetectionPolicyTest.java
index 739a5a2..ca614b3 100644
--- a/policy/src/test/java/brooklyn/policy/ha/MemberFailureDetectionPolicyTest.java
+++ b/policy/src/test/java/brooklyn/policy/ha/MemberFailureDetectionPolicyTest.java
@@ -62,7 +62,7 @@
     
     @AfterMethod(alwaysRun=true)
     public void tearDown() throws Exception {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
     
     @Test(groups="Integration") // Has a 1 second wait
diff --git a/policy/src/test/java/brooklyn/policy/loadbalancing/AbstractLoadBalancingPolicyTest.groovy b/policy/src/test/java/brooklyn/policy/loadbalancing/AbstractLoadBalancingPolicyTest.groovy
index 9df9ad5..6df7c5a 100644
--- a/policy/src/test/java/brooklyn/policy/loadbalancing/AbstractLoadBalancingPolicyTest.groovy
+++ b/policy/src/test/java/brooklyn/policy/loadbalancing/AbstractLoadBalancingPolicyTest.groovy
@@ -70,7 +70,8 @@
     
     @AfterMethod(alwaysRun=true)
     public void after() {
-        if (app != null) Entities.destroy(app);
+        if (policy != null) policy.destroy();
+        if (app != null) Entities.destroyAll(app);
     }
     
     // Using this utility, as it gives more info about the workrates of all containers rather than just the one that differs    
diff --git a/policy/src/test/java/brooklyn/policy/loadbalancing/BalanceableWorkerPoolTest.groovy b/policy/src/test/java/brooklyn/policy/loadbalancing/BalanceableWorkerPoolTest.groovy
index e039561..73a8aa4 100644
--- a/policy/src/test/java/brooklyn/policy/loadbalancing/BalanceableWorkerPoolTest.groovy
+++ b/policy/src/test/java/brooklyn/policy/loadbalancing/BalanceableWorkerPoolTest.groovy
@@ -48,7 +48,7 @@
     
     @AfterMethod(alwaysRun=true)
     public void after() {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
     
     @Test
diff --git a/sandbox/nosql/src/test/java/brooklyn/entity/nosql/mongodb/MongoDbTest.groovy b/sandbox/nosql/src/test/java/brooklyn/entity/nosql/mongodb/MongoDbTest.groovy
index ad0d40d..ef9d5ce 100644
--- a/sandbox/nosql/src/test/java/brooklyn/entity/nosql/mongodb/MongoDbTest.groovy
+++ b/sandbox/nosql/src/test/java/brooklyn/entity/nosql/mongodb/MongoDbTest.groovy
@@ -38,7 +38,7 @@
     @AfterMethod(alwaysRun = true)
     public void shutdownApp() {
         if (testApplication != null) {
-            Entities.destroy(testApplication)
+            Entities.destroyAll(testApplication)
         }
     }
 
diff --git a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessEntity.java b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessEntity.java
index 420001c..36443dc 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessEntity.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessEntity.java
@@ -18,10 +18,10 @@
 import brooklyn.entity.drivers.DriverDependentEntity;
 import brooklyn.entity.trait.Startable;
 import brooklyn.event.AttributeSensor;
-import brooklyn.event.adapter.ConfigSensorAdapter;
 import brooklyn.event.adapter.SensorRegistry;
 import brooklyn.event.basic.BasicAttributeSensor;
 import brooklyn.event.basic.BasicConfigKey;
+import brooklyn.event.feed.ConfigToAttributes;
 import brooklyn.location.Location;
 import brooklyn.location.MachineLocation;
 import brooklyn.location.MachineProvisioningLocation;
@@ -382,7 +382,7 @@
         // Note: must only apply config-sensors after adding to locations and creating driver; 
         // otherwise can't do things like acquire free port from location, or allowing driver to set up ports
         if (sensorRegistry == null) sensorRegistry = new SensorRegistry(this);
-        ConfigSensorAdapter.apply(this);
+        ConfigToAttributes.apply(this);
         
 		setAttribute(HOSTNAME, machine.getAddress().getHostName());
 		setAttribute(ADDRESS, machine.getAddress().getHostAddress());
diff --git a/software/base/src/main/java/brooklyn/entity/java/VanillaJavaApp.java b/software/base/src/main/java/brooklyn/entity/java/VanillaJavaApp.java
index 1e70003..aaaccc6 100644
--- a/software/base/src/main/java/brooklyn/entity/java/VanillaJavaApp.java
+++ b/software/base/src/main/java/brooklyn/entity/java/VanillaJavaApp.java
@@ -12,10 +12,10 @@
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.Entity;
 import brooklyn.entity.basic.SoftwareProcessEntity;
-import brooklyn.event.adapter.ConfigSensorAdapter;
 import brooklyn.event.adapter.FunctionSensorAdapter;
 import brooklyn.event.adapter.JmxSensorAdapter;
 import brooklyn.event.basic.BasicConfigKey;
+import brooklyn.event.feed.ConfigToAttributes;
 import brooklyn.util.MutableList;
 import brooklyn.util.MutableMap;
 import brooklyn.util.flags.SetFromFlag;
@@ -92,7 +92,7 @@
     protected void connectSensors() {
         super.connectSensors();
         
-        sensorRegistry.register(new ConfigSensorAdapter());
+        ConfigToAttributes.apply(this);
         
         if ( ((VanillaJavaAppDriver)getDriver()).isJmxEnabled() ) {
             jmxPollPeriod = (jmxPollPeriod > 0) ? jmxPollPeriod : 500;
diff --git a/software/base/src/test/java/brooklyn/entity/basic/lifecycle/JavaSoftwareProcessSshDriverIntegrationTest.groovy b/software/base/src/test/java/brooklyn/entity/basic/lifecycle/JavaSoftwareProcessSshDriverIntegrationTest.groovy
index 1ffe774..49eeb17 100644
--- a/software/base/src/test/java/brooklyn/entity/basic/lifecycle/JavaSoftwareProcessSshDriverIntegrationTest.groovy
+++ b/software/base/src/test/java/brooklyn/entity/basic/lifecycle/JavaSoftwareProcessSshDriverIntegrationTest.groovy
@@ -37,7 +37,7 @@
 
     @AfterMethod(alwaysRun=true)
     public void shutdown() {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
 
     @Test(groups = "Integration")
diff --git a/software/base/src/test/java/brooklyn/entity/java/JavaOptsTest.java b/software/base/src/test/java/brooklyn/entity/java/JavaOptsTest.java
index eeb8abd..ee0c4e5 100644
--- a/software/base/src/test/java/brooklyn/entity/java/JavaOptsTest.java
+++ b/software/base/src/test/java/brooklyn/entity/java/JavaOptsTest.java
@@ -84,7 +84,7 @@
     
     @AfterMethod(alwaysRun=true)
     public void tearDown() {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
     
     @Test
diff --git a/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppRebindTest.java b/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppRebindTest.java
index 34ab7dc..c0732d5 100644
--- a/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppRebindTest.java
+++ b/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppRebindTest.java
@@ -54,7 +54,7 @@
 
     @AfterMethod(alwaysRun = true)
     public void tearDown() throws Exception {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
         if (mementoDir != null) RebindTestUtils.deleteMementoDir(mementoDir);
     }
     
diff --git a/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppTest.groovy b/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppTest.groovy
index 7b3b6e6..c5b32e9 100644
--- a/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppTest.groovy
+++ b/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppTest.groovy
@@ -66,7 +66,7 @@
 
     @AfterMethod(alwaysRun = true)
     public void tearDown() {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
 
     @Test
diff --git a/software/base/src/test/java/brooklyn/event/feed/jmx/JmxFeedTest.java b/software/base/src/test/java/brooklyn/event/feed/jmx/JmxFeedTest.java
index 7bb5c03..1a0f1c7 100644
--- a/software/base/src/test/java/brooklyn/event/feed/jmx/JmxFeedTest.java
+++ b/software/base/src/test/java/brooklyn/event/feed/jmx/JmxFeedTest.java
@@ -111,7 +111,7 @@
         if (feed != null) feed.stop();
         if (jmxHelper != null) jmxHelper.disconnect();
         if (jmxService != null) jmxService.shutdown();
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
         feed = null;
     }
 
@@ -345,7 +345,7 @@
                     assertEquals(received.get(0).getValue(), "abc");
                 }});
         } finally {
-            if (app != null) Entities.destroy(app);
+            if (app != null) Entities.destroyAll(app);
         }
     }
     
diff --git a/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlIntegrationTest.groovy b/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlIntegrationTest.groovy
index eabdc4e..22bc9e9 100644
--- a/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlIntegrationTest.groovy
+++ b/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlIntegrationTest.groovy
@@ -33,7 +33,7 @@
     @AfterMethod(alwaysRun=true)
     public void ensureShutDown() {
         if (tapp != null) {
-            Entities.destroy(tapp)
+            Entities.destroyAll(tapp)
             tapp = null;
         };
     }
diff --git a/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlIntegrationTest.groovy b/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlIntegrationTest.groovy
index 757deb4..7a6441a 100644
--- a/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlIntegrationTest.groovy
+++ b/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlIntegrationTest.groovy
@@ -30,7 +30,7 @@
     @AfterMethod(alwaysRun = true)
     public void ensureShutDown() {
         if (tapp != null) {
-            Entities.destroy(tapp)
+            Entities.destroyAll(tapp)
             tapp = null;
         };
     }
diff --git a/software/messaging/src/test/java/brooklyn/entity/messaging/activemq/ActiveMQEc2LiveTest.groovy b/software/messaging/src/test/java/brooklyn/entity/messaging/activemq/ActiveMQEc2LiveTest.groovy
index 0b1616d..504be27 100644
--- a/software/messaging/src/test/java/brooklyn/entity/messaging/activemq/ActiveMQEc2LiveTest.groovy
+++ b/software/messaging/src/test/java/brooklyn/entity/messaging/activemq/ActiveMQEc2LiveTest.groovy
@@ -71,7 +71,7 @@
 
     @AfterMethod(alwaysRun=true)
     public void tearDown() {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
 
     /**
diff --git a/software/messaging/src/test/java/brooklyn/entity/messaging/activemq/ActiveMQIntegrationTest.groovy b/software/messaging/src/test/java/brooklyn/entity/messaging/activemq/ActiveMQIntegrationTest.groovy
index b91b8e4..b8c1924 100644
--- a/software/messaging/src/test/java/brooklyn/entity/messaging/activemq/ActiveMQIntegrationTest.groovy
+++ b/software/messaging/src/test/java/brooklyn/entity/messaging/activemq/ActiveMQIntegrationTest.groovy
@@ -48,7 +48,7 @@
 
     @AfterMethod(groups = "Integration")
     public void shutdown() {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
 
     /**
diff --git a/software/messaging/src/test/java/brooklyn/entity/messaging/qpid/QpidIntegrationTest.groovy b/software/messaging/src/test/java/brooklyn/entity/messaging/qpid/QpidIntegrationTest.groovy
index 9d26781..9bc0aa5 100644
--- a/software/messaging/src/test/java/brooklyn/entity/messaging/qpid/QpidIntegrationTest.groovy
+++ b/software/messaging/src/test/java/brooklyn/entity/messaging/qpid/QpidIntegrationTest.groovy
@@ -49,7 +49,7 @@
 
     @AfterMethod(alwaysRun=true)
     public void shutdown() {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
 
     /**
diff --git a/software/messaging/src/test/java/brooklyn/entity/messaging/rabbit/RabbitIntegrationTest.groovy b/software/messaging/src/test/java/brooklyn/entity/messaging/rabbit/RabbitIntegrationTest.groovy
index 9e81df6..d6fa706 100644
--- a/software/messaging/src/test/java/brooklyn/entity/messaging/rabbit/RabbitIntegrationTest.groovy
+++ b/software/messaging/src/test/java/brooklyn/entity/messaging/rabbit/RabbitIntegrationTest.groovy
@@ -57,7 +57,7 @@
 
     @AfterMethod(alwaysRun = true)
     public void shutdown() {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
 
     /**
diff --git a/software/osgi/src/main/java/brooklyn/entity/osgi/karaf/KarafContainer.java b/software/osgi/src/main/java/brooklyn/entity/osgi/karaf/KarafContainer.java
index d8098c2..3abcf4e 100644
--- a/software/osgi/src/main/java/brooklyn/entity/osgi/karaf/KarafContainer.java
+++ b/software/osgi/src/main/java/brooklyn/entity/osgi/karaf/KarafContainer.java
@@ -28,7 +28,6 @@
 import brooklyn.entity.java.UsesJmx;
 import brooklyn.event.SensorEvent;
 import brooklyn.event.SensorEventListener;
-import brooklyn.event.adapter.ConfigSensorAdapter;
 import brooklyn.event.adapter.JmxHelper;
 import brooklyn.event.adapter.JmxObjectNameAdapter;
 import brooklyn.event.adapter.JmxPostProcessors;
@@ -38,6 +37,7 @@
 import brooklyn.event.basic.BasicConfigKey;
 import brooklyn.event.basic.MapConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
+import brooklyn.event.feed.ConfigToAttributes;
 import brooklyn.util.MutableMap;
 import brooklyn.util.ResourceUtils;
 import brooklyn.util.exceptions.Exceptions;
@@ -165,7 +165,8 @@
         //use of "properties.{user,password}" is non-standard; is that requried? use default jmxUser, jmxPassword flags?
         setAttribute(JMX_CONTEXT, String.format("karaf-%s", getConfig(KARAF_NAME.getConfigKey())));
         
-        sensorRegistry.register(new ConfigSensorAdapter());
+        ConfigToAttributes.apply(this);
+        
         jmxAdapter = sensorRegistry.register(new JmxSensorAdapter(MutableMap.of("period", 500)));
 
         JmxObjectNameAdapter karafAdminObjectNameAdapter = jmxAdapter.objectName(String.format(KARAF_ADMIN, getConfig(KARAF_NAME.getConfigKey())));
diff --git a/software/osgi/src/test/java/brooklyn/entity/osgi/karaf/KarafContainerTest.groovy b/software/osgi/src/test/java/brooklyn/entity/osgi/karaf/KarafContainerTest.groovy
index 5b376f5..fd4c584 100644
--- a/software/osgi/src/test/java/brooklyn/entity/osgi/karaf/KarafContainerTest.groovy
+++ b/software/osgi/src/test/java/brooklyn/entity/osgi/karaf/KarafContainerTest.groovy
@@ -33,7 +33,7 @@
 
     @AfterMethod(alwaysRun=true)
     public void shutdown() {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
 
     @Test(groups = "Integration")
diff --git a/software/webapp/src/main/java/brooklyn/entity/dns/AbstractGeoDnsService.groovy b/software/webapp/src/main/java/brooklyn/entity/dns/AbstractGeoDnsService.groovy
index eb42588..a7566bf 100644
--- a/software/webapp/src/main/java/brooklyn/entity/dns/AbstractGeoDnsService.groovy
+++ b/software/webapp/src/main/java/brooklyn/entity/dns/AbstractGeoDnsService.groovy
@@ -1,10 +1,8 @@
 package brooklyn.entity.dns
 
-import brooklyn.entity.Entity;
-import java.util.Map
-import java.util.Set
 import java.util.concurrent.Executors
 import java.util.concurrent.ScheduledFuture
+import java.util.concurrent.ThreadFactory
 import java.util.concurrent.TimeUnit
 
 import org.slf4j.Logger
@@ -16,14 +14,15 @@
 import brooklyn.entity.basic.Attributes
 import brooklyn.entity.basic.DynamicGroup
 import brooklyn.entity.basic.Lifecycle
-import brooklyn.entity.trait.Startable;
+import brooklyn.entity.trait.Startable
 import brooklyn.entity.webapp.WebAppService
-import brooklyn.event.Sensor;
+import brooklyn.event.Sensor
 import brooklyn.event.basic.BasicAttributeSensor
 import brooklyn.location.geo.HostGeoInfo
 
 import com.google.common.base.Throwables
 import com.google.common.collect.ImmutableMap
+import com.google.common.util.concurrent.ThreadFactoryBuilder
 
 
 abstract class AbstractGeoDnsService extends AbstractEntity {
@@ -87,7 +86,12 @@
             log.warn("GeoDns $this has no targetEntityProvider, ignoring")
             return;
         }
-        poll = Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(
+        
+        // TODO Should re-use the execution manager's thread pool, somehow
+        ThreadFactory threadFactory = new ThreadFactoryBuilder()
+                .setNameFormat("brooklyn-geodnsservice-%d")
+                .build();
+        poll = Executors.newSingleThreadScheduledExecutor(threadFactory).scheduleAtFixedRate(
             new Runnable() {
                 public void run() {
                     try {
@@ -102,6 +106,7 @@
             }, 0, 5, TimeUnit.SECONDS
         );
     }
+    
     protected void endPoll() {
         if (poll!=null) {
             if (log.isDebugEnabled()) log.debug("GeoDns $this ending poll");
diff --git a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxController.java b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxController.java
index 93b0c01..e7cb590 100644
--- a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxController.java
+++ b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxController.java
@@ -23,8 +23,8 @@
 import brooklyn.entity.proxy.ProxySslConfig;
 import brooklyn.event.SensorEvent;
 import brooklyn.event.SensorEventListener;
-import brooklyn.event.adapter.ConfigSensorAdapter;
 import brooklyn.event.basic.BasicConfigKey;
+import brooklyn.event.feed.ConfigToAttributes;
 import brooklyn.event.feed.http.HttpFeed;
 import brooklyn.event.feed.http.HttpPollConfig;
 import brooklyn.event.feed.http.HttpPollValue;
@@ -113,7 +113,7 @@
     public void connectSensors() {
         super.connectSensors();
         
-        ConfigSensorAdapter.apply(this);
+        ConfigToAttributes.apply(this);
 
         // "up" is defined as returning a valid HTTP response from nginx (including a 404 etc)
         httpFeed = HttpFeed.builder()
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/tomcat/TomcatServer.java b/software/webapp/src/main/java/brooklyn/entity/webapp/tomcat/TomcatServer.java
index 221f8be..f44bf38 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/tomcat/TomcatServer.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/tomcat/TomcatServer.java
@@ -20,6 +20,7 @@
 import brooklyn.event.basic.BasicAttributeSensor;
 import brooklyn.event.basic.BasicConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
+import brooklyn.event.feed.ConfigToAttributes;
 import brooklyn.event.feed.jmx.JmxAttributePollConfig;
 import brooklyn.event.feed.jmx.JmxFeed;
 import brooklyn.location.basic.PortRanges;
@@ -70,7 +71,7 @@
     public void connectSensors() {
         super.connectSensors();
 
-        sensorRegistry.register(new ConfigSensorAdapter());
+        ConfigToAttributes.apply(this);
 
         Map<String, Object> flags = new LinkedHashMap<String, Object>();
         flags.put("period", new TimeDuration(0, 0, 0, 0, 500));
diff --git a/software/webapp/src/test/java/brooklyn/entity/proxy/UrlMappingTest.java b/software/webapp/src/test/java/brooklyn/entity/proxy/UrlMappingTest.java
index 1e0be4f..f7930b1 100644
--- a/software/webapp/src/test/java/brooklyn/entity/proxy/UrlMappingTest.java
+++ b/software/webapp/src/test/java/brooklyn/entity/proxy/UrlMappingTest.java
@@ -69,7 +69,7 @@
 
     @AfterMethod(alwaysRun=true)
     public void shutdown() {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
         if (mementoDir != null) RebindTestUtils.deleteMementoDir(mementoDir);
     }
 
diff --git a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxAmazonTest.groovy b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxAmazonTest.groovy
index 347baca..1ea471a 100644
--- a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxAmazonTest.groovy
+++ b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxAmazonTest.groovy
@@ -48,7 +48,7 @@
 
     @AfterMethod(groups = "Live")
     public void shutdown() {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
     
     @BeforeMethod(groups = "Live")
diff --git a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxClusterIntegrationTest.java b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxClusterIntegrationTest.java
index 88b097c..619d414 100644
--- a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxClusterIntegrationTest.java
+++ b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxClusterIntegrationTest.java
@@ -65,7 +65,7 @@
 
     @AfterMethod(groups = "Integration", alwaysRun=true)
     public void shutdown() {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
 
     @Test(groups = "Integration")
diff --git a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxHttpsSslIntegrationTest.groovy b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxHttpsSslIntegrationTest.groovy
index d260a35..2d6daaf 100644
--- a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxHttpsSslIntegrationTest.groovy
+++ b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxHttpsSslIntegrationTest.groovy
@@ -44,7 +44,7 @@
 
     @AfterMethod(alwaysRun=true)
     public void shutdown() {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
 
     /**
diff --git a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxIntegrationTest.groovy b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxIntegrationTest.groovy
index 4d57183..31933b0 100644
--- a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxIntegrationTest.groovy
+++ b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxIntegrationTest.groovy
@@ -43,7 +43,7 @@
 
     @AfterMethod(groups = "Integration", alwaysRun=true)
     public void shutdown() {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
 
     /**
diff --git a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxLightIntegrationTest.java b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxLightIntegrationTest.java
index 8e8bc1e..e5be4ab 100644
--- a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxLightIntegrationTest.java
+++ b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxLightIntegrationTest.java
@@ -43,7 +43,7 @@
 
     @AfterMethod(alwaysRun=true)
     public void shutdown() {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
 
     // FIXME Fails because getting addEntity callback for group members while nginx is still starting,
diff --git a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxRebindIntegrationTest.java b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxRebindIntegrationTest.java
index 51cf407..07f3923 100644
--- a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxRebindIntegrationTest.java
+++ b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxRebindIntegrationTest.java
@@ -77,8 +77,8 @@
         	monitor.terminate();
         }
         if (executor != null) executor.shutdownNow();
-        if (newApp != null) Entities.destroy(newApp);
-        if (origApp != null && origManagementContext.isRunning()) Entities.destroy(origApp);
+        if (newApp != null) Entities.destroyAll(newApp);
+        if (origApp != null && origManagementContext.isRunning()) Entities.destroyAll(origApp);
         if (mementoDir != null) RebindTestUtils.deleteMementoDir(mementoDir);
     }
 
diff --git a/software/webapp/src/test/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterTest.java b/software/webapp/src/test/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterTest.java
index 9160e68..0133c16 100644
--- a/software/webapp/src/test/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterTest.java
+++ b/software/webapp/src/test/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterTest.java
@@ -47,7 +47,7 @@
     
     @AfterMethod(alwaysRun=true)
     public void tearDown() throws Exception {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
     
     @Test(groups="Integration")
diff --git a/software/webapp/src/test/java/brooklyn/entity/webapp/ElasticJavaWebAppServiceIntegrationTest.groovy b/software/webapp/src/test/java/brooklyn/entity/webapp/ElasticJavaWebAppServiceIntegrationTest.groovy
index 931b1e1..5973f0d 100644
--- a/software/webapp/src/test/java/brooklyn/entity/webapp/ElasticJavaWebAppServiceIntegrationTest.groovy
+++ b/software/webapp/src/test/java/brooklyn/entity/webapp/ElasticJavaWebAppServiceIntegrationTest.groovy
@@ -23,7 +23,7 @@
 
     @AfterMethod(alwaysRun=true)
     public void tearDown() throws Exception {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
     }
 
     @Test(groups = "Integration")
diff --git a/software/webapp/src/test/java/brooklyn/entity/webapp/WebAppIntegrationTest.groovy b/software/webapp/src/test/java/brooklyn/entity/webapp/WebAppIntegrationTest.groovy
index fef597c..38e452f 100644
--- a/software/webapp/src/test/java/brooklyn/entity/webapp/WebAppIntegrationTest.groovy
+++ b/software/webapp/src/test/java/brooklyn/entity/webapp/WebAppIntegrationTest.groovy
@@ -86,7 +86,7 @@
             try {
                 entity.stop();
             } finally {
-                if (app != null) Entities.destroy(app);
+                if (app != null) Entities.destroyAll(app);
             }
         }
     }
diff --git a/software/webapp/src/test/java/brooklyn/entity/webapp/jboss/ControlledDynamicWebAppClusterRebindIntegrationTest.java b/software/webapp/src/test/java/brooklyn/entity/webapp/jboss/ControlledDynamicWebAppClusterRebindIntegrationTest.java
index aabc872..051ad1d 100644
--- a/software/webapp/src/test/java/brooklyn/entity/webapp/jboss/ControlledDynamicWebAppClusterRebindIntegrationTest.java
+++ b/software/webapp/src/test/java/brooklyn/entity/webapp/jboss/ControlledDynamicWebAppClusterRebindIntegrationTest.java
@@ -73,8 +73,8 @@
         	monitor.terminate();
         }
         if (executor != null) executor.shutdownNow();
-        if (newApp != null) Entities.destroy(newApp);
-        if (origApp != null) Entities.destroy(origApp);
+        if (newApp != null) Entities.destroyAll(newApp);
+        if (origApp != null) Entities.destroyAll(origApp);
         if (mementoDir != null) RebindTestUtils.deleteMementoDir(mementoDir);
     }
 
diff --git a/software/webapp/src/test/java/brooklyn/entity/webapp/jboss/DynamicWebAppClusterRebindIntegrationTest.java b/software/webapp/src/test/java/brooklyn/entity/webapp/jboss/DynamicWebAppClusterRebindIntegrationTest.java
index f414280..3d5ad2d 100644
--- a/software/webapp/src/test/java/brooklyn/entity/webapp/jboss/DynamicWebAppClusterRebindIntegrationTest.java
+++ b/software/webapp/src/test/java/brooklyn/entity/webapp/jboss/DynamicWebAppClusterRebindIntegrationTest.java
@@ -71,8 +71,8 @@
         	monitor.terminate();
         }
         if (executor != null) executor.shutdownNow();
-        if (newApp != null) Entities.destroy(newApp);
-        if (origApp != null) Entities.destroy(origApp);
+        if (newApp != null) Entities.destroyAll(newApp);
+        if (origApp != null) Entities.destroyAll(origApp);
         if (mementoDir != null) RebindTestUtils.deleteMementoDir(mementoDir);
     }
 
diff --git a/software/webapp/src/test/java/brooklyn/entity/webapp/jboss/Jboss7ServerIntegrationTest.java b/software/webapp/src/test/java/brooklyn/entity/webapp/jboss/Jboss7ServerIntegrationTest.java
index d1cb743..5d85542 100644
--- a/software/webapp/src/test/java/brooklyn/entity/webapp/jboss/Jboss7ServerIntegrationTest.java
+++ b/software/webapp/src/test/java/brooklyn/entity/webapp/jboss/Jboss7ServerIntegrationTest.java
@@ -54,7 +54,7 @@
 
     @AfterMethod(alwaysRun=true)
     public void tearDown() throws Exception {
-        if (app != null) Entities.destroy(app);
+        if (app != null) Entities.destroyAll(app);
         if (keystoreFile != null) keystoreFile.delete();
     }
 
diff --git a/software/webapp/src/test/java/brooklyn/entity/webapp/jboss/Jboss7ServerRebindIntegrationTest.java b/software/webapp/src/test/java/brooklyn/entity/webapp/jboss/Jboss7ServerRebindIntegrationTest.java
index 155593f..834434f 100644
--- a/software/webapp/src/test/java/brooklyn/entity/webapp/jboss/Jboss7ServerRebindIntegrationTest.java
+++ b/software/webapp/src/test/java/brooklyn/entity/webapp/jboss/Jboss7ServerRebindIntegrationTest.java
@@ -70,8 +70,8 @@
         	monitor.terminate();
         }
         if (executor != null) executor.shutdownNow();
-        if (newApp != null) Entities.destroy(newApp);
-        if (origApp != null) Entities.destroy(origApp);
+        if (newApp != null) Entities.destroyAll(newApp);
+        if (origApp != null) Entities.destroyAll(origApp);
         if (mementoDir != null) RebindTestUtils.deleteMementoDir(mementoDir);
     }